1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_ci#if !defined(SOL_TCP) && defined(IPPROTO_TCP) 28d4afb5ceSopenharmony_ci#define SOL_TCP IPPROTO_TCP 29d4afb5ceSopenharmony_ci#endif 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ciconst char * const method_names[] = { 32d4afb5ceSopenharmony_ci "GET", "POST", 33d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 34d4afb5ceSopenharmony_ci "OPTIONS", "PUT", "PATCH", "DELETE", 35d4afb5ceSopenharmony_ci#endif 36d4afb5ceSopenharmony_ci "CONNECT", "HEAD", 37d4afb5ceSopenharmony_ci#ifdef LWS_WITH_HTTP2 38d4afb5ceSopenharmony_ci ":path", 39d4afb5ceSopenharmony_ci#endif 40d4afb5ceSopenharmony_ci }; 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 43d4afb5ceSopenharmony_cistatic const char * const intermediates[] = { "private", "public" }; 44d4afb5ceSopenharmony_ci#endif 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ci/* 47d4afb5ceSopenharmony_ci * return 0: all done 48d4afb5ceSopenharmony_ci * 1: nonfatal error 49d4afb5ceSopenharmony_ci * <0: fatal error 50d4afb5ceSopenharmony_ci * 51d4afb5ceSopenharmony_ci * REQUIRES CONTEXT LOCK HELD 52d4afb5ceSopenharmony_ci */ 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 55d4afb5ceSopenharmony_ci 56d4afb5ceSopenharmony_cistruct vh_sock_args { 57d4afb5ceSopenharmony_ci const struct lws_context_creation_info *info; 58d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 59d4afb5ceSopenharmony_ci int af; 60d4afb5ceSopenharmony_ci}; 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_cistatic int 64d4afb5ceSopenharmony_cicheck_extant(struct lws_dll2 *d, void *user) 65d4afb5ceSopenharmony_ci{ 66d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(d, struct lws, listen_list); 67d4afb5ceSopenharmony_ci struct vh_sock_args *a = (struct vh_sock_args *)user; 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci if (!lws_vhost_compare_listen(wsi->a.vhost, a->vhost)) 70d4afb5ceSopenharmony_ci return 0; 71d4afb5ceSopenharmony_ci 72d4afb5ceSopenharmony_ci if (wsi->af != a ->af) 73d4afb5ceSopenharmony_ci return 0; 74d4afb5ceSopenharmony_ci 75d4afb5ceSopenharmony_ci lwsl_notice(" using listen skt from vhost %s\n", wsi->a.vhost->name); 76d4afb5ceSopenharmony_ci 77d4afb5ceSopenharmony_ci return 1; 78d4afb5ceSopenharmony_ci} 79d4afb5ceSopenharmony_ci 80d4afb5ceSopenharmony_ci/* 81d4afb5ceSopenharmony_ci * Creates a single listen socket of a specific AF 82d4afb5ceSopenharmony_ci */ 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ciint 85d4afb5ceSopenharmony_ci_lws_vhost_init_server_af(struct vh_sock_args *a) 86d4afb5ceSopenharmony_ci{ 87d4afb5ceSopenharmony_ci struct lws_context *cx = a->vhost->context; 88d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 89d4afb5ceSopenharmony_ci int n, opt = 1, limit = 1; 90d4afb5ceSopenharmony_ci lws_sockfd_type sockfd; 91d4afb5ceSopenharmony_ci struct lws *wsi; 92d4afb5ceSopenharmony_ci int m = 0, is; 93d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 94d4afb5ceSopenharmony_ci int value = 1; 95d4afb5ceSopenharmony_ci#endif 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_ci (void)method_names; 98d4afb5ceSopenharmony_ci (void)opt; 99d4afb5ceSopenharmony_ci 100d4afb5ceSopenharmony_ci lwsl_info("%s: af %d\n", __func__, (int)a->af); 101d4afb5ceSopenharmony_ci 102d4afb5ceSopenharmony_ci if (lws_vhost_foreach_listen_wsi(a->vhost->context, a, check_extant)) 103d4afb5ceSopenharmony_ci return 0; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_cideal: 106d4afb5ceSopenharmony_ci 107d4afb5ceSopenharmony_ci if (a->vhost->iface) { 108d4afb5ceSopenharmony_ci 109d4afb5ceSopenharmony_ci /* 110d4afb5ceSopenharmony_ci * let's check before we do anything else about the disposition 111d4afb5ceSopenharmony_ci * of the interface he wants to bind to... 112d4afb5ceSopenharmony_ci */ 113d4afb5ceSopenharmony_ci is = lws_socket_bind(a->vhost, NULL, LWS_SOCK_INVALID, 114d4afb5ceSopenharmony_ci a->vhost->listen_port, a->vhost->iface, 115d4afb5ceSopenharmony_ci a->af); 116d4afb5ceSopenharmony_ci lwsl_debug("initial if check says %d\n", is); 117d4afb5ceSopenharmony_ci 118d4afb5ceSopenharmony_ci if (is == LWS_ITOSA_BUSY) 119d4afb5ceSopenharmony_ci /* treat as fatal */ 120d4afb5ceSopenharmony_ci return -1; 121d4afb5ceSopenharmony_ci 122d4afb5ceSopenharmony_ci lws_start_foreach_llp(struct lws_vhost **, pv, 123d4afb5ceSopenharmony_ci cx->no_listener_vhost_list) { 124d4afb5ceSopenharmony_ci if (is >= LWS_ITOSA_USABLE && *pv == a->vhost) { 125d4afb5ceSopenharmony_ci /* on the list and shouldn't be: remove it */ 126d4afb5ceSopenharmony_ci lwsl_debug("deferred iface: removing vh %s\n", 127d4afb5ceSopenharmony_ci (*pv)->name); 128d4afb5ceSopenharmony_ci *pv = a->vhost->no_listener_vhost_list; 129d4afb5ceSopenharmony_ci a->vhost->no_listener_vhost_list = NULL; 130d4afb5ceSopenharmony_ci goto done_list; 131d4afb5ceSopenharmony_ci } 132d4afb5ceSopenharmony_ci if (is < LWS_ITOSA_USABLE && *pv == a->vhost) 133d4afb5ceSopenharmony_ci goto done_list; 134d4afb5ceSopenharmony_ci } lws_end_foreach_llp(pv, no_listener_vhost_list); 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci /* not on the list... */ 137d4afb5ceSopenharmony_ci 138d4afb5ceSopenharmony_ci if (is < LWS_ITOSA_USABLE) { 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ci /* ... but needs to be: so add it */ 141d4afb5ceSopenharmony_ci 142d4afb5ceSopenharmony_ci lwsl_debug("deferred iface: adding vh %s\n", 143d4afb5ceSopenharmony_ci a->vhost->name); 144d4afb5ceSopenharmony_ci a->vhost->no_listener_vhost_list = 145d4afb5ceSopenharmony_ci cx->no_listener_vhost_list; 146d4afb5ceSopenharmony_ci cx->no_listener_vhost_list = a->vhost; 147d4afb5ceSopenharmony_ci } 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_cidone_list: 150d4afb5ceSopenharmony_ci 151d4afb5ceSopenharmony_ci switch (is) { 152d4afb5ceSopenharmony_ci default: 153d4afb5ceSopenharmony_ci break; 154d4afb5ceSopenharmony_ci case LWS_ITOSA_NOT_EXIST: 155d4afb5ceSopenharmony_ci /* can't add it */ 156d4afb5ceSopenharmony_ci if (!a->info) 157d4afb5ceSopenharmony_ci return -1; 158d4afb5ceSopenharmony_ci 159d4afb5ceSopenharmony_ci /* first time */ 160d4afb5ceSopenharmony_ci lwsl_err("%s: VH %s: iface %s port %d DOESN'T EXIST\n", 161d4afb5ceSopenharmony_ci __func__, a->vhost->name, a->vhost->iface, 162d4afb5ceSopenharmony_ci a->vhost->listen_port); 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci return (a->info->options & 165d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) == 166d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ? 167d4afb5ceSopenharmony_ci -1 : 1; 168d4afb5ceSopenharmony_ci 169d4afb5ceSopenharmony_ci case LWS_ITOSA_NOT_USABLE: 170d4afb5ceSopenharmony_ci /* can't add it */ 171d4afb5ceSopenharmony_ci if (!a->info) /* first time */ 172d4afb5ceSopenharmony_ci return -1; 173d4afb5ceSopenharmony_ci 174d4afb5ceSopenharmony_ci lwsl_err("%s: VH %s: iface %s port %d NOT USABLE\n", 175d4afb5ceSopenharmony_ci __func__, a->vhost->name, a->vhost->iface, 176d4afb5ceSopenharmony_ci a->vhost->listen_port); 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci return (a->info->options & 179d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) == 180d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ? 181d4afb5ceSopenharmony_ci -1 : 1; 182d4afb5ceSopenharmony_ci } 183d4afb5ceSopenharmony_ci } 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci (void)n; 186d4afb5ceSopenharmony_ci#if defined(__linux__) 187d4afb5ceSopenharmony_ci /* 188d4afb5ceSopenharmony_ci * A Unix domain sockets cannot be bound multiple times, even if we 189d4afb5ceSopenharmony_ci * set the SO_REUSE* options on. 190d4afb5ceSopenharmony_ci * 191d4afb5ceSopenharmony_ci * However on recent linux, each thread is able to independently listen. 192d4afb5ceSopenharmony_ci * 193d4afb5ceSopenharmony_ci * So we can assume creating just one listening socket for a multi- 194d4afb5ceSopenharmony_ci * threaded environment will typically work. 195d4afb5ceSopenharmony_ci */ 196d4afb5ceSopenharmony_ci if (a->af != AF_UNIX) 197d4afb5ceSopenharmony_ci limit = cx->count_threads; 198d4afb5ceSopenharmony_ci#endif 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_ci for (m = 0; m < limit; m++) { 201d4afb5ceSopenharmony_ci 202d4afb5ceSopenharmony_ci sockfd = lws_fi(&a->vhost->fic, "listenskt") ? 203d4afb5ceSopenharmony_ci LWS_SOCK_INVALID : 204d4afb5ceSopenharmony_ci socket(a->af, SOCK_STREAM, 0); 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci if (sockfd == LWS_SOCK_INVALID) { 207d4afb5ceSopenharmony_ci lwsl_err("ERROR opening socket\n"); 208d4afb5ceSopenharmony_ci return 1; 209d4afb5ceSopenharmony_ci } 210d4afb5ceSopenharmony_ci 211d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) 212d4afb5ceSopenharmony_ci#if (defined(WIN32) || defined(_WIN32)) && defined(SO_EXCLUSIVEADDRUSE) 213d4afb5ceSopenharmony_ci /* 214d4afb5ceSopenharmony_ci * only accept that we are the only listener on the port 215d4afb5ceSopenharmony_ci * https://msdn.microsoft.com/zh-tw/library/ 216d4afb5ceSopenharmony_ci * windows/desktop/ms740621(v=vs.85).aspx 217d4afb5ceSopenharmony_ci * 218d4afb5ceSopenharmony_ci * for lws, to match Linux, we default to exclusive listen 219d4afb5ceSopenharmony_ci */ 220d4afb5ceSopenharmony_ci if (!lws_check_opt(a->vhost->options, 221d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) { 222d4afb5ceSopenharmony_ci if (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 223d4afb5ceSopenharmony_ci (const void *)&opt, sizeof(opt)) < 0) { 224d4afb5ceSopenharmony_ci lwsl_err("reuseaddr failed\n"); 225d4afb5ceSopenharmony_ci compatible_close(sockfd); 226d4afb5ceSopenharmony_ci return -1; 227d4afb5ceSopenharmony_ci } 228d4afb5ceSopenharmony_ci } else 229d4afb5ceSopenharmony_ci#endif 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci /* 232d4afb5ceSopenharmony_ci * allow us to restart even if old sockets in TIME_WAIT 233d4afb5ceSopenharmony_ci */ 234d4afb5ceSopenharmony_ci if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 235d4afb5ceSopenharmony_ci (const void *)&opt, sizeof(opt)) < 0) { 236d4afb5ceSopenharmony_ci lwsl_err("reuseaddr failed\n"); 237d4afb5ceSopenharmony_ci compatible_close(sockfd); 238d4afb5ceSopenharmony_ci return -1; 239d4afb5ceSopenharmony_ci } 240d4afb5ceSopenharmony_ci 241d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) && defined(IPV6_V6ONLY) 242d4afb5ceSopenharmony_ci /* 243d4afb5ceSopenharmony_ci * If we have an ipv6 listen socket, it only accepts ipv6. 244d4afb5ceSopenharmony_ci * 245d4afb5ceSopenharmony_ci * There will be a separate ipv4 listen socket if that's 246d4afb5ceSopenharmony_ci * enabled. 247d4afb5ceSopenharmony_ci */ 248d4afb5ceSopenharmony_ci if (a->af == AF_INET6 && 249d4afb5ceSopenharmony_ci setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, 250d4afb5ceSopenharmony_ci (const void*)&value, sizeof(value)) < 0) { 251d4afb5ceSopenharmony_ci compatible_close(sockfd); 252d4afb5ceSopenharmony_ci return -1; 253d4afb5ceSopenharmony_ci } 254d4afb5ceSopenharmony_ci#endif 255d4afb5ceSopenharmony_ci 256d4afb5ceSopenharmony_ci#if defined(__linux__) && defined(SO_REUSEPORT) 257d4afb5ceSopenharmony_ci /* keep coverity happy */ 258d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1 259d4afb5ceSopenharmony_ci n = 1; 260d4afb5ceSopenharmony_ci#else 261d4afb5ceSopenharmony_ci n = lws_check_opt(a->vhost->options, 262d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE); 263d4afb5ceSopenharmony_ci#endif 264d4afb5ceSopenharmony_ci if (n || cx->count_threads > 1) /* ... also implied by threads > 1 */ 265d4afb5ceSopenharmony_ci if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, 266d4afb5ceSopenharmony_ci (const void *)&opt, sizeof(opt)) < 0) { 267d4afb5ceSopenharmony_ci compatible_close(sockfd); 268d4afb5ceSopenharmony_ci return -1; 269d4afb5ceSopenharmony_ci } 270d4afb5ceSopenharmony_ci#endif 271d4afb5ceSopenharmony_ci#endif 272d4afb5ceSopenharmony_ci lws_plat_set_socket_options(a->vhost, sockfd, 0); 273d4afb5ceSopenharmony_ci 274d4afb5ceSopenharmony_ci is = lws_socket_bind(a->vhost, NULL, sockfd, 275d4afb5ceSopenharmony_ci a->vhost->listen_port, 276d4afb5ceSopenharmony_ci a->vhost->iface, a->af); 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ci if (is == LWS_ITOSA_BUSY) { 279d4afb5ceSopenharmony_ci /* treat as fatal */ 280d4afb5ceSopenharmony_ci compatible_close(sockfd); 281d4afb5ceSopenharmony_ci 282d4afb5ceSopenharmony_ci return -1; 283d4afb5ceSopenharmony_ci } 284d4afb5ceSopenharmony_ci 285d4afb5ceSopenharmony_ci /* 286d4afb5ceSopenharmony_ci * There is a race where the network device may come up and then 287d4afb5ceSopenharmony_ci * go away and fail here. So correctly handle unexpected failure 288d4afb5ceSopenharmony_ci * here despite we earlier confirmed it. 289d4afb5ceSopenharmony_ci */ 290d4afb5ceSopenharmony_ci if (is < 0) { 291d4afb5ceSopenharmony_ci lwsl_info("%s: lws_socket_bind says %d\n", __func__, is); 292d4afb5ceSopenharmony_ci compatible_close(sockfd); 293d4afb5ceSopenharmony_ci if (a->vhost->iface) 294d4afb5ceSopenharmony_ci goto deal; 295d4afb5ceSopenharmony_ci return -1; 296d4afb5ceSopenharmony_ci } 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_ci /* 299d4afb5ceSopenharmony_ci * Create the listen wsi and customize it 300d4afb5ceSopenharmony_ci */ 301d4afb5ceSopenharmony_ci 302d4afb5ceSopenharmony_ci lws_context_lock(cx, __func__); 303d4afb5ceSopenharmony_ci wsi = __lws_wsi_create_with_role(cx, m, &role_ops_listen, NULL); 304d4afb5ceSopenharmony_ci lws_context_unlock(cx); 305d4afb5ceSopenharmony_ci if (wsi == NULL) { 306d4afb5ceSopenharmony_ci lwsl_err("Out of mem\n"); 307d4afb5ceSopenharmony_ci goto bail; 308d4afb5ceSopenharmony_ci } 309d4afb5ceSopenharmony_ci 310d4afb5ceSopenharmony_ci wsi->af = (uint8_t)a->af; 311d4afb5ceSopenharmony_ci 312d4afb5ceSopenharmony_ci#ifdef LWS_WITH_UNIX_SOCK 313d4afb5ceSopenharmony_ci if (!LWS_UNIX_SOCK_ENABLED(a->vhost)) 314d4afb5ceSopenharmony_ci#endif 315d4afb5ceSopenharmony_ci { 316d4afb5ceSopenharmony_ci wsi->unix_skt = 1; 317d4afb5ceSopenharmony_ci a->vhost->listen_port = is; 318d4afb5ceSopenharmony_ci 319d4afb5ceSopenharmony_ci lwsl_debug("%s: lws_socket_bind says %d\n", __func__, is); 320d4afb5ceSopenharmony_ci } 321d4afb5ceSopenharmony_ci 322d4afb5ceSopenharmony_ci wsi->desc.sockfd = sockfd; 323d4afb5ceSopenharmony_ci wsi->a.protocol = a->vhost->protocols; 324d4afb5ceSopenharmony_ci lws_vhost_bind_wsi(a->vhost, wsi); 325d4afb5ceSopenharmony_ci wsi->listener = 1; 326d4afb5ceSopenharmony_ci 327d4afb5ceSopenharmony_ci if (wsi->a.context->event_loop_ops->init_vhost_listen_wsi) 328d4afb5ceSopenharmony_ci wsi->a.context->event_loop_ops->init_vhost_listen_wsi(wsi); 329d4afb5ceSopenharmony_ci 330d4afb5ceSopenharmony_ci pt = &cx->pt[m]; 331d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 332d4afb5ceSopenharmony_ci 333d4afb5ceSopenharmony_ci if (__insert_wsi_socket_into_fds(cx, wsi)) { 334d4afb5ceSopenharmony_ci lwsl_notice("inserting wsi socket into fds failed\n"); 335d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 336d4afb5ceSopenharmony_ci goto bail; 337d4afb5ceSopenharmony_ci } 338d4afb5ceSopenharmony_ci 339d4afb5ceSopenharmony_ci lws_dll2_add_tail(&wsi->listen_list, &a->vhost->listen_wsi); 340d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 341d4afb5ceSopenharmony_ci 342d4afb5ceSopenharmony_ci#if defined(WIN32) && defined(TCP_FASTOPEN) 343d4afb5ceSopenharmony_ci if (a->vhost->fo_listen_queue) { 344d4afb5ceSopenharmony_ci int optval = 1; 345d4afb5ceSopenharmony_ci if (setsockopt(wsi->desc.sockfd, IPPROTO_TCP, 346d4afb5ceSopenharmony_ci TCP_FASTOPEN, 347d4afb5ceSopenharmony_ci (const char*)&optval, sizeof(optval)) < 0) { 348d4afb5ceSopenharmony_ci int error = LWS_ERRNO; 349d4afb5ceSopenharmony_ci lwsl_warn("%s: TCP_NODELAY failed with error %d\n", 350d4afb5ceSopenharmony_ci __func__, error); 351d4afb5ceSopenharmony_ci } 352d4afb5ceSopenharmony_ci } 353d4afb5ceSopenharmony_ci#else 354d4afb5ceSopenharmony_ci#if defined(TCP_FASTOPEN) 355d4afb5ceSopenharmony_ci if (a->vhost->fo_listen_queue) { 356d4afb5ceSopenharmony_ci int qlen = a->vhost->fo_listen_queue; 357d4afb5ceSopenharmony_ci 358d4afb5ceSopenharmony_ci if (setsockopt(wsi->desc.sockfd, SOL_TCP, TCP_FASTOPEN, 359d4afb5ceSopenharmony_ci &qlen, sizeof(qlen))) 360d4afb5ceSopenharmony_ci lwsl_warn("%s: TCP_FASTOPEN failed\n", __func__); 361d4afb5ceSopenharmony_ci } 362d4afb5ceSopenharmony_ci#endif 363d4afb5ceSopenharmony_ci#endif 364d4afb5ceSopenharmony_ci 365d4afb5ceSopenharmony_ci n = listen(wsi->desc.sockfd, LWS_SOMAXCONN); 366d4afb5ceSopenharmony_ci if (n < 0) { 367d4afb5ceSopenharmony_ci lwsl_err("listen failed with error %d\n", LWS_ERRNO); 368d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->listen_list); 369d4afb5ceSopenharmony_ci __remove_wsi_socket_from_fds(wsi); 370d4afb5ceSopenharmony_ci goto bail; 371d4afb5ceSopenharmony_ci } 372d4afb5ceSopenharmony_ci 373d4afb5ceSopenharmony_ci if (wsi) 374d4afb5ceSopenharmony_ci __lws_lc_tag(a->vhost->context, 375d4afb5ceSopenharmony_ci &a->vhost->context->lcg[LWSLCG_WSI], 376d4afb5ceSopenharmony_ci &wsi->lc, "listen|%s|%s|%d", 377d4afb5ceSopenharmony_ci a->vhost->name, 378d4afb5ceSopenharmony_ci a->vhost->iface ? a->vhost->iface : "", 379d4afb5ceSopenharmony_ci (int)a->vhost->listen_port); 380d4afb5ceSopenharmony_ci 381d4afb5ceSopenharmony_ci } /* for each thread able to independently listen */ 382d4afb5ceSopenharmony_ci 383d4afb5ceSopenharmony_ci if (!lws_check_opt(cx->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) { 384d4afb5ceSopenharmony_ci#ifdef LWS_WITH_UNIX_SOCK 385d4afb5ceSopenharmony_ci if (a->af == AF_UNIX) 386d4afb5ceSopenharmony_ci lwsl_info(" Listening on \"%s\"\n", a->vhost->iface); 387d4afb5ceSopenharmony_ci else 388d4afb5ceSopenharmony_ci#endif 389d4afb5ceSopenharmony_ci lwsl_info(" Listening on %s:%d\n", 390d4afb5ceSopenharmony_ci a->vhost->iface, 391d4afb5ceSopenharmony_ci a->vhost->listen_port); 392d4afb5ceSopenharmony_ci } 393d4afb5ceSopenharmony_ci 394d4afb5ceSopenharmony_ci // info->port = vhost->listen_port; 395d4afb5ceSopenharmony_ci 396d4afb5ceSopenharmony_ci return 0; 397d4afb5ceSopenharmony_ci 398d4afb5ceSopenharmony_cibail: 399d4afb5ceSopenharmony_ci compatible_close(sockfd); 400d4afb5ceSopenharmony_ci 401d4afb5ceSopenharmony_ci return -1; 402d4afb5ceSopenharmony_ci} 403d4afb5ceSopenharmony_ci 404d4afb5ceSopenharmony_ci 405d4afb5ceSopenharmony_ciint 406d4afb5ceSopenharmony_ci_lws_vhost_init_server(const struct lws_context_creation_info *info, 407d4afb5ceSopenharmony_ci struct lws_vhost *vhost) 408d4afb5ceSopenharmony_ci{ 409d4afb5ceSopenharmony_ci struct vh_sock_args a; 410d4afb5ceSopenharmony_ci int n; 411d4afb5ceSopenharmony_ci 412d4afb5ceSopenharmony_ci a.info = info; 413d4afb5ceSopenharmony_ci a.vhost = vhost; 414d4afb5ceSopenharmony_ci 415d4afb5ceSopenharmony_ci if (info) { 416d4afb5ceSopenharmony_ci vhost->iface = info->iface; 417d4afb5ceSopenharmony_ci vhost->listen_port = info->port; 418d4afb5ceSopenharmony_ci } 419d4afb5ceSopenharmony_ci 420d4afb5ceSopenharmony_ci /* set up our external listening socket we serve on */ 421d4afb5ceSopenharmony_ci 422d4afb5ceSopenharmony_ci if (vhost->listen_port == CONTEXT_PORT_NO_LISTEN || 423d4afb5ceSopenharmony_ci vhost->listen_port == CONTEXT_PORT_NO_LISTEN_SERVER) 424d4afb5ceSopenharmony_ci return 0; 425d4afb5ceSopenharmony_ci 426d4afb5ceSopenharmony_ci /* 427d4afb5ceSopenharmony_ci * Let's figure out what AF(s) we want this vhost to listen on. 428d4afb5ceSopenharmony_ci * 429d4afb5ceSopenharmony_ci * We want AF_UNIX alone if that's what's told 430d4afb5ceSopenharmony_ci */ 431d4afb5ceSopenharmony_ci 432d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UNIX_SOCK) 433d4afb5ceSopenharmony_ci /* 434d4afb5ceSopenharmony_ci * If unix socket, ask for that and we are done 435d4afb5ceSopenharmony_ci */ 436d4afb5ceSopenharmony_ci if (LWS_UNIX_SOCK_ENABLED(vhost)) { 437d4afb5ceSopenharmony_ci a.af = AF_UNIX; 438d4afb5ceSopenharmony_ci goto single; 439d4afb5ceSopenharmony_ci } 440d4afb5ceSopenharmony_ci#endif 441d4afb5ceSopenharmony_ci 442d4afb5ceSopenharmony_ci /* 443d4afb5ceSopenharmony_ci * We may support both ipv4 and ipv6, but get a numeric vhost listen 444d4afb5ceSopenharmony_ci * iface that is unambiguously ipv4 or ipv6, meaning we can only listen 445d4afb5ceSopenharmony_ci * for the related AF then. 446d4afb5ceSopenharmony_ci */ 447d4afb5ceSopenharmony_ci 448d4afb5ceSopenharmony_ci if (vhost->iface) { 449d4afb5ceSopenharmony_ci uint8_t buf[16]; 450d4afb5ceSopenharmony_ci int q; 451d4afb5ceSopenharmony_ci 452d4afb5ceSopenharmony_ci q = lws_parse_numeric_address(vhost->iface, buf, sizeof(buf)); 453d4afb5ceSopenharmony_ci 454d4afb5ceSopenharmony_ci if (q == 4) { 455d4afb5ceSopenharmony_ci a.af = AF_INET; 456d4afb5ceSopenharmony_ci goto single; 457d4afb5ceSopenharmony_ci } 458d4afb5ceSopenharmony_ci 459d4afb5ceSopenharmony_ci if (q == 16) { 460d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 461d4afb5ceSopenharmony_ci if (LWS_IPV6_ENABLED(vhost)) { 462d4afb5ceSopenharmony_ci a.af = AF_INET6; 463d4afb5ceSopenharmony_ci goto single; 464d4afb5ceSopenharmony_ci } 465d4afb5ceSopenharmony_ci#endif 466d4afb5ceSopenharmony_ci lwsl_err("%s: ipv6 not supported on %s\n", __func__, 467d4afb5ceSopenharmony_ci vhost->name); 468d4afb5ceSopenharmony_ci return 1; 469d4afb5ceSopenharmony_ci } 470d4afb5ceSopenharmony_ci } 471d4afb5ceSopenharmony_ci 472d4afb5ceSopenharmony_ci /* 473d4afb5ceSopenharmony_ci * ... if we make it here, we would want to listen on AF_INET and 474d4afb5ceSopenharmony_ci * AF_INET6 unless one or the other is forbidden 475d4afb5ceSopenharmony_ci */ 476d4afb5ceSopenharmony_ci 477d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 478d4afb5ceSopenharmony_ci if (!(LWS_IPV6_ENABLED(vhost) && 479d4afb5ceSopenharmony_ci (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) && 480d4afb5ceSopenharmony_ci (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE))) { 481d4afb5ceSopenharmony_ci#endif 482d4afb5ceSopenharmony_ci a.af = AF_INET; 483d4afb5ceSopenharmony_ci n = _lws_vhost_init_server_af(&a); 484d4afb5ceSopenharmony_ci if (n) 485d4afb5ceSopenharmony_ci return n; 486d4afb5ceSopenharmony_ci 487d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 488d4afb5ceSopenharmony_ci } 489d4afb5ceSopenharmony_ci if (LWS_IPV6_ENABLED(vhost)) { 490d4afb5ceSopenharmony_ci a.af = AF_INET6; 491d4afb5ceSopenharmony_ci goto single; 492d4afb5ceSopenharmony_ci } 493d4afb5ceSopenharmony_ci#endif 494d4afb5ceSopenharmony_ci 495d4afb5ceSopenharmony_ci return 0; 496d4afb5ceSopenharmony_ci 497d4afb5ceSopenharmony_cisingle: 498d4afb5ceSopenharmony_ci return _lws_vhost_init_server_af(&a); 499d4afb5ceSopenharmony_ci} 500d4afb5ceSopenharmony_ci 501d4afb5ceSopenharmony_ci#endif 502d4afb5ceSopenharmony_ci 503d4afb5ceSopenharmony_cistruct lws_vhost * 504d4afb5ceSopenharmony_cilws_select_vhost(struct lws_context *context, int port, const char *servername) 505d4afb5ceSopenharmony_ci{ 506d4afb5ceSopenharmony_ci struct lws_vhost *vhost = context->vhost_list; 507d4afb5ceSopenharmony_ci const char *p; 508d4afb5ceSopenharmony_ci int n, colon; 509d4afb5ceSopenharmony_ci 510d4afb5ceSopenharmony_ci n = (int)strlen(servername); 511d4afb5ceSopenharmony_ci colon = n; 512d4afb5ceSopenharmony_ci p = strchr(servername, ':'); 513d4afb5ceSopenharmony_ci if (p) 514d4afb5ceSopenharmony_ci colon = lws_ptr_diff(p, servername); 515d4afb5ceSopenharmony_ci 516d4afb5ceSopenharmony_ci /* Priotity 1: first try exact matches */ 517d4afb5ceSopenharmony_ci 518d4afb5ceSopenharmony_ci while (vhost) { 519d4afb5ceSopenharmony_ci if (port == vhost->listen_port && 520d4afb5ceSopenharmony_ci !strncmp(vhost->name, servername, (unsigned int)colon)) { 521d4afb5ceSopenharmony_ci lwsl_info("SNI: Found: %s\n", servername); 522d4afb5ceSopenharmony_ci return vhost; 523d4afb5ceSopenharmony_ci } 524d4afb5ceSopenharmony_ci vhost = vhost->vhost_next; 525d4afb5ceSopenharmony_ci } 526d4afb5ceSopenharmony_ci 527d4afb5ceSopenharmony_ci /* 528d4afb5ceSopenharmony_ci * Priority 2: if no exact matches, try matching *.vhost-name 529d4afb5ceSopenharmony_ci * unintentional matches are possible but resolve to x.com for *.x.com 530d4afb5ceSopenharmony_ci * which is reasonable. If exact match exists we already chose it and 531d4afb5ceSopenharmony_ci * never reach here. SSL will still fail it if the cert doesn't allow 532d4afb5ceSopenharmony_ci * *.x.com. 533d4afb5ceSopenharmony_ci */ 534d4afb5ceSopenharmony_ci vhost = context->vhost_list; 535d4afb5ceSopenharmony_ci while (vhost) { 536d4afb5ceSopenharmony_ci int m = (int)strlen(vhost->name); 537d4afb5ceSopenharmony_ci if (port && port == vhost->listen_port && 538d4afb5ceSopenharmony_ci m <= (colon - 2) && 539d4afb5ceSopenharmony_ci servername[colon - m - 1] == '.' && 540d4afb5ceSopenharmony_ci !strncmp(vhost->name, servername + colon - m, (unsigned int)m)) { 541d4afb5ceSopenharmony_ci lwsl_info("SNI: Found %s on wildcard: %s\n", 542d4afb5ceSopenharmony_ci servername, vhost->name); 543d4afb5ceSopenharmony_ci return vhost; 544d4afb5ceSopenharmony_ci } 545d4afb5ceSopenharmony_ci vhost = vhost->vhost_next; 546d4afb5ceSopenharmony_ci } 547d4afb5ceSopenharmony_ci 548d4afb5ceSopenharmony_ci /* Priority 3: match the first vhost on our port */ 549d4afb5ceSopenharmony_ci 550d4afb5ceSopenharmony_ci vhost = context->vhost_list; 551d4afb5ceSopenharmony_ci while (vhost) { 552d4afb5ceSopenharmony_ci if (port && port == vhost->listen_port) { 553d4afb5ceSopenharmony_ci lwsl_info("%s: vhost match to %s based on port %d\n", 554d4afb5ceSopenharmony_ci __func__, vhost->name, port); 555d4afb5ceSopenharmony_ci return vhost; 556d4afb5ceSopenharmony_ci } 557d4afb5ceSopenharmony_ci vhost = vhost->vhost_next; 558d4afb5ceSopenharmony_ci } 559d4afb5ceSopenharmony_ci 560d4afb5ceSopenharmony_ci /* no match */ 561d4afb5ceSopenharmony_ci 562d4afb5ceSopenharmony_ci return NULL; 563d4afb5ceSopenharmony_ci} 564d4afb5ceSopenharmony_ci 565d4afb5ceSopenharmony_cistatic const struct lws_mimetype { 566d4afb5ceSopenharmony_ci const char *extension; 567d4afb5ceSopenharmony_ci const char *mimetype; 568d4afb5ceSopenharmony_ci} server_mimetypes[] = { 569d4afb5ceSopenharmony_ci { ".html", "text/html" }, 570d4afb5ceSopenharmony_ci { ".htm", "text/html" }, 571d4afb5ceSopenharmony_ci { ".js", "text/javascript" }, 572d4afb5ceSopenharmony_ci { ".css", "text/css" }, 573d4afb5ceSopenharmony_ci { ".png", "image/png" }, 574d4afb5ceSopenharmony_ci { ".jpg", "image/jpeg" }, 575d4afb5ceSopenharmony_ci { ".jpeg", "image/jpeg" }, 576d4afb5ceSopenharmony_ci { ".ico", "image/x-icon" }, 577d4afb5ceSopenharmony_ci { ".gif", "image/gif" }, 578d4afb5ceSopenharmony_ci { ".svg", "image/svg+xml" }, 579d4afb5ceSopenharmony_ci { ".ttf", "application/x-font-ttf" }, 580d4afb5ceSopenharmony_ci { ".otf", "application/font-woff" }, 581d4afb5ceSopenharmony_ci { ".woff", "application/font-woff" }, 582d4afb5ceSopenharmony_ci { ".woff2", "application/font-woff2" }, 583d4afb5ceSopenharmony_ci { ".gz", "application/gzip" }, 584d4afb5ceSopenharmony_ci { ".txt", "text/plain" }, 585d4afb5ceSopenharmony_ci { ".xml", "application/xml" }, 586d4afb5ceSopenharmony_ci { ".json", "application/json" }, 587d4afb5ceSopenharmony_ci { ".mjs", "text/javascript" }, 588d4afb5ceSopenharmony_ci}; 589d4afb5ceSopenharmony_ci 590d4afb5ceSopenharmony_ciconst char * 591d4afb5ceSopenharmony_cilws_get_mimetype(const char *file, const struct lws_http_mount *m) 592d4afb5ceSopenharmony_ci{ 593d4afb5ceSopenharmony_ci const struct lws_protocol_vhost_options *pvo; 594d4afb5ceSopenharmony_ci size_t n = strlen(file), len, i; 595d4afb5ceSopenharmony_ci const char *fallback_mimetype = NULL; 596d4afb5ceSopenharmony_ci const struct lws_mimetype *mt; 597d4afb5ceSopenharmony_ci 598d4afb5ceSopenharmony_ci /* prioritize user-defined mimetypes */ 599d4afb5ceSopenharmony_ci for (pvo = m ? m->extra_mimetypes : NULL; pvo; pvo = pvo->next) { 600d4afb5ceSopenharmony_ci /* ie, match anything */ 601d4afb5ceSopenharmony_ci if (!fallback_mimetype && pvo->name[0] == '*') { 602d4afb5ceSopenharmony_ci fallback_mimetype = pvo->value; 603d4afb5ceSopenharmony_ci continue; 604d4afb5ceSopenharmony_ci } 605d4afb5ceSopenharmony_ci 606d4afb5ceSopenharmony_ci len = strlen(pvo->name); 607d4afb5ceSopenharmony_ci if (n > len && !strcasecmp(&file[n - len], pvo->name)) { 608d4afb5ceSopenharmony_ci lwsl_info("%s: match to user mimetype: %s\n", __func__, 609d4afb5ceSopenharmony_ci pvo->value); 610d4afb5ceSopenharmony_ci return pvo->value; 611d4afb5ceSopenharmony_ci } 612d4afb5ceSopenharmony_ci } 613d4afb5ceSopenharmony_ci 614d4afb5ceSopenharmony_ci /* fallback to server-defined mimetypes */ 615d4afb5ceSopenharmony_ci for (i = 0; i < LWS_ARRAY_SIZE(server_mimetypes); ++i) { 616d4afb5ceSopenharmony_ci mt = &server_mimetypes[i]; 617d4afb5ceSopenharmony_ci 618d4afb5ceSopenharmony_ci len = strlen(mt->extension); 619d4afb5ceSopenharmony_ci if (n > len && !strcasecmp(&file[n - len], mt->extension)) { 620d4afb5ceSopenharmony_ci lwsl_info("%s: match to server mimetype: %s\n", __func__, 621d4afb5ceSopenharmony_ci mt->mimetype); 622d4afb5ceSopenharmony_ci return mt->mimetype; 623d4afb5ceSopenharmony_ci } 624d4afb5ceSopenharmony_ci } 625d4afb5ceSopenharmony_ci 626d4afb5ceSopenharmony_ci /* fallback to '*' if defined */ 627d4afb5ceSopenharmony_ci if (fallback_mimetype) { 628d4afb5ceSopenharmony_ci lwsl_info("%s: match to any mimetype: %s\n", __func__, 629d4afb5ceSopenharmony_ci fallback_mimetype); 630d4afb5ceSopenharmony_ci return fallback_mimetype; 631d4afb5ceSopenharmony_ci } 632d4afb5ceSopenharmony_ci 633d4afb5ceSopenharmony_ci return NULL; 634d4afb5ceSopenharmony_ci} 635d4afb5ceSopenharmony_ci 636d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 637d4afb5ceSopenharmony_cistatic lws_fop_flags_t 638d4afb5ceSopenharmony_cilws_vfs_prepare_flags(struct lws *wsi) 639d4afb5ceSopenharmony_ci{ 640d4afb5ceSopenharmony_ci lws_fop_flags_t f = 0; 641d4afb5ceSopenharmony_ci 642d4afb5ceSopenharmony_ci if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)) 643d4afb5ceSopenharmony_ci return f; 644d4afb5ceSopenharmony_ci 645d4afb5ceSopenharmony_ci if (strstr(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING), 646d4afb5ceSopenharmony_ci "gzip")) { 647d4afb5ceSopenharmony_ci lwsl_info("client indicates GZIP is acceptable\n"); 648d4afb5ceSopenharmony_ci f |= LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP; 649d4afb5ceSopenharmony_ci } 650d4afb5ceSopenharmony_ci 651d4afb5ceSopenharmony_ci return f; 652d4afb5ceSopenharmony_ci} 653d4afb5ceSopenharmony_ci 654d4afb5ceSopenharmony_cistatic int 655d4afb5ceSopenharmony_cilws_http_serve(struct lws *wsi, char *uri, const char *origin, 656d4afb5ceSopenharmony_ci const struct lws_http_mount *m) 657d4afb5ceSopenharmony_ci{ 658d4afb5ceSopenharmony_ci const struct lws_protocol_vhost_options *pvo = m->interpret; 659d4afb5ceSopenharmony_ci struct lws_process_html_args args; 660d4afb5ceSopenharmony_ci const char *mimetype; 661d4afb5ceSopenharmony_ci#if !defined(_WIN32_WCE) 662d4afb5ceSopenharmony_ci const struct lws_plat_file_ops *fops; 663d4afb5ceSopenharmony_ci const char *vpath; 664d4afb5ceSopenharmony_ci lws_fop_flags_t fflags = LWS_O_RDONLY; 665d4afb5ceSopenharmony_ci#if defined(WIN32) && defined(LWS_HAVE__STAT32I64) 666d4afb5ceSopenharmony_ci struct _stat32i64 st; 667d4afb5ceSopenharmony_ci#else 668d4afb5ceSopenharmony_ci struct stat st; 669d4afb5ceSopenharmony_ci#endif 670d4afb5ceSopenharmony_ci int spin = 0; 671d4afb5ceSopenharmony_ci#endif 672d4afb5ceSopenharmony_ci char path[256], sym[2048]; 673d4afb5ceSopenharmony_ci unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p; 674d4afb5ceSopenharmony_ci unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE; 675d4afb5ceSopenharmony_ci#if !defined(WIN32) && !defined(LWS_PLAT_FREERTOS) 676d4afb5ceSopenharmony_ci size_t len; 677d4afb5ceSopenharmony_ci#endif 678d4afb5ceSopenharmony_ci int n; 679d4afb5ceSopenharmony_ci 680d4afb5ceSopenharmony_ci wsi->handling_404 = 0; 681d4afb5ceSopenharmony_ci if (!wsi->a.vhost) 682d4afb5ceSopenharmony_ci return -1; 683d4afb5ceSopenharmony_ci 684d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 685d4afb5ceSopenharmony_ci if (wsi->a.vhost->http.error_document_404 && 686d4afb5ceSopenharmony_ci !strcmp(uri, wsi->a.vhost->http.error_document_404)) 687d4afb5ceSopenharmony_ci wsi->handling_404 = 1; 688d4afb5ceSopenharmony_ci#endif 689d4afb5ceSopenharmony_ci 690d4afb5ceSopenharmony_ci lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri); 691d4afb5ceSopenharmony_ci 692d4afb5ceSopenharmony_ci#if !defined(_WIN32_WCE) 693d4afb5ceSopenharmony_ci 694d4afb5ceSopenharmony_ci fflags |= lws_vfs_prepare_flags(wsi); 695d4afb5ceSopenharmony_ci 696d4afb5ceSopenharmony_ci do { 697d4afb5ceSopenharmony_ci spin++; 698d4afb5ceSopenharmony_ci fops = lws_vfs_select_fops(wsi->a.context->fops, path, &vpath); 699d4afb5ceSopenharmony_ci 700d4afb5ceSopenharmony_ci if (wsi->http.fop_fd) 701d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 702d4afb5ceSopenharmony_ci 703d4afb5ceSopenharmony_ci wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->a.context->fops, 704d4afb5ceSopenharmony_ci path, vpath, &fflags); 705d4afb5ceSopenharmony_ci if (!wsi->http.fop_fd) { 706d4afb5ceSopenharmony_ci lwsl_info("%s: Unable to open '%s': errno %d\n", 707d4afb5ceSopenharmony_ci __func__, path, errno); 708d4afb5ceSopenharmony_ci 709d4afb5ceSopenharmony_ci return 1; 710d4afb5ceSopenharmony_ci } 711d4afb5ceSopenharmony_ci 712d4afb5ceSopenharmony_ci /* if it can't be statted, don't try */ 713d4afb5ceSopenharmony_ci if (fflags & LWS_FOP_FLAG_VIRTUAL) 714d4afb5ceSopenharmony_ci break; 715d4afb5ceSopenharmony_ci#if defined(LWS_PLAT_FREERTOS) 716d4afb5ceSopenharmony_ci break; 717d4afb5ceSopenharmony_ci#endif 718d4afb5ceSopenharmony_ci#if !defined(WIN32) 719d4afb5ceSopenharmony_ci if (fstat(wsi->http.fop_fd->fd, &st)) { 720d4afb5ceSopenharmony_ci lwsl_info("unable to stat %s\n", path); 721d4afb5ceSopenharmony_ci goto notfound; 722d4afb5ceSopenharmony_ci } 723d4afb5ceSopenharmony_ci#else 724d4afb5ceSopenharmony_ci#if defined(LWS_HAVE__STAT32I64) 725d4afb5ceSopenharmony_ci { 726d4afb5ceSopenharmony_ci WCHAR buf[MAX_PATH]; 727d4afb5ceSopenharmony_ci MultiByteToWideChar(CP_UTF8, 0, path, -1, buf, LWS_ARRAY_SIZE(buf)); 728d4afb5ceSopenharmony_ci if (_wstat32i64(buf, &st)) { 729d4afb5ceSopenharmony_ci lwsl_info("unable to stat %s\n", path); 730d4afb5ceSopenharmony_ci goto notfound; 731d4afb5ceSopenharmony_ci } 732d4afb5ceSopenharmony_ci } 733d4afb5ceSopenharmony_ci#else 734d4afb5ceSopenharmony_ci if (stat(path, &st)) { 735d4afb5ceSopenharmony_ci lwsl_info("unable to stat %s\n", path); 736d4afb5ceSopenharmony_ci goto notfound; 737d4afb5ceSopenharmony_ci } 738d4afb5ceSopenharmony_ci#endif 739d4afb5ceSopenharmony_ci#endif 740d4afb5ceSopenharmony_ci 741d4afb5ceSopenharmony_ci wsi->http.fop_fd->mod_time = (uint32_t)st.st_mtime; 742d4afb5ceSopenharmony_ci fflags |= LWS_FOP_FLAG_MOD_TIME_VALID; 743d4afb5ceSopenharmony_ci 744d4afb5ceSopenharmony_ci#if !defined(WIN32) && !defined(LWS_PLAT_FREERTOS) 745d4afb5ceSopenharmony_ci if ((S_IFMT & st.st_mode) == S_IFLNK) { 746d4afb5ceSopenharmony_ci len = (size_t)readlink(path, sym, sizeof(sym) - 1); 747d4afb5ceSopenharmony_ci if (len) { 748d4afb5ceSopenharmony_ci lwsl_err("Failed to read link %s\n", path); 749d4afb5ceSopenharmony_ci goto notfound; 750d4afb5ceSopenharmony_ci } 751d4afb5ceSopenharmony_ci sym[len] = '\0'; 752d4afb5ceSopenharmony_ci lwsl_debug("symlink %s -> %s\n", path, sym); 753d4afb5ceSopenharmony_ci lws_snprintf(path, sizeof(path) - 1, "%s", sym); 754d4afb5ceSopenharmony_ci } 755d4afb5ceSopenharmony_ci#endif 756d4afb5ceSopenharmony_ci if ((S_IFMT & st.st_mode) == S_IFDIR) { 757d4afb5ceSopenharmony_ci lwsl_debug("default filename append to dir\n"); 758d4afb5ceSopenharmony_ci lws_snprintf(path, sizeof(path) - 1, "%s/%s/%s", 759d4afb5ceSopenharmony_ci origin, uri, m->def ? m->def : "index.html"); 760d4afb5ceSopenharmony_ci } 761d4afb5ceSopenharmony_ci 762d4afb5ceSopenharmony_ci } while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5); 763d4afb5ceSopenharmony_ci 764d4afb5ceSopenharmony_ci if (spin == 5) 765d4afb5ceSopenharmony_ci lwsl_err("symlink loop %s \n", path); 766d4afb5ceSopenharmony_ci 767d4afb5ceSopenharmony_ci n = sprintf(sym, "%08llX%08lX", 768d4afb5ceSopenharmony_ci (unsigned long long)lws_vfs_get_length(wsi->http.fop_fd), 769d4afb5ceSopenharmony_ci (unsigned long)lws_vfs_get_mod_time(wsi->http.fop_fd)); 770d4afb5ceSopenharmony_ci 771d4afb5ceSopenharmony_ci /* disable ranges if IF_RANGE token invalid */ 772d4afb5ceSopenharmony_ci 773d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_RANGE)) 774d4afb5ceSopenharmony_ci if (strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_RANGE))) 775d4afb5ceSopenharmony_ci /* differs - defeat Range: */ 776d4afb5ceSopenharmony_ci wsi->http.ah->frag_index[WSI_TOKEN_HTTP_RANGE] = 0; 777d4afb5ceSopenharmony_ci 778d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) { 779d4afb5ceSopenharmony_ci /* 780d4afb5ceSopenharmony_ci * he thinks he has some version of it already, 781d4afb5ceSopenharmony_ci * check if the tag matches 782d4afb5ceSopenharmony_ci */ 783d4afb5ceSopenharmony_ci if (!strcmp(sym, lws_hdr_simple_ptr(wsi, 784d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_IF_NONE_MATCH))) { 785d4afb5ceSopenharmony_ci 786d4afb5ceSopenharmony_ci char cache_control[50], *cc = "no-store"; 787d4afb5ceSopenharmony_ci int cclen = 8; 788d4afb5ceSopenharmony_ci 789d4afb5ceSopenharmony_ci lwsl_debug("%s: ETAG match %s %s\n", __func__, 790d4afb5ceSopenharmony_ci uri, origin); 791d4afb5ceSopenharmony_ci 792d4afb5ceSopenharmony_ci /* we don't need to send the payload */ 793d4afb5ceSopenharmony_ci if (lws_add_http_header_status(wsi, 794d4afb5ceSopenharmony_ci HTTP_STATUS_NOT_MODIFIED, &p, end)) { 795d4afb5ceSopenharmony_ci lwsl_err("%s: failed adding not modified\n", 796d4afb5ceSopenharmony_ci __func__); 797d4afb5ceSopenharmony_ci return -1; 798d4afb5ceSopenharmony_ci } 799d4afb5ceSopenharmony_ci 800d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 801d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_ETAG, 802d4afb5ceSopenharmony_ci (unsigned char *)sym, n, &p, end)) 803d4afb5ceSopenharmony_ci return -1; 804d4afb5ceSopenharmony_ci 805d4afb5ceSopenharmony_ci /* but we still need to send cache control... */ 806d4afb5ceSopenharmony_ci 807d4afb5ceSopenharmony_ci if (m->cache_max_age && m->cache_reusable) { 808d4afb5ceSopenharmony_ci if (!m->cache_revalidate) { 809d4afb5ceSopenharmony_ci cc = cache_control; 810d4afb5ceSopenharmony_ci cclen = sprintf(cache_control, 811d4afb5ceSopenharmony_ci "%s, max-age=%u", 812d4afb5ceSopenharmony_ci intermediates[wsi->cache_intermediaries], 813d4afb5ceSopenharmony_ci m->cache_max_age); 814d4afb5ceSopenharmony_ci } else { 815d4afb5ceSopenharmony_ci cc = cache_control; 816d4afb5ceSopenharmony_ci cclen = sprintf(cache_control, 817d4afb5ceSopenharmony_ci "must-revalidate, %s, max-age=%u", 818d4afb5ceSopenharmony_ci intermediates[wsi->cache_intermediaries], 819d4afb5ceSopenharmony_ci m->cache_max_age); 820d4afb5ceSopenharmony_ci } 821d4afb5ceSopenharmony_ci } 822d4afb5ceSopenharmony_ci 823d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 824d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CACHE_CONTROL, 825d4afb5ceSopenharmony_ci (unsigned char *)cc, cclen, &p, end)) 826d4afb5ceSopenharmony_ci return -1; 827d4afb5ceSopenharmony_ci 828d4afb5ceSopenharmony_ci if (lws_finalize_http_header(wsi, &p, end)) 829d4afb5ceSopenharmony_ci return -1; 830d4afb5ceSopenharmony_ci 831d4afb5ceSopenharmony_ci n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), 832d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_HEADERS | 833d4afb5ceSopenharmony_ci LWS_WRITE_H2_STREAM_END); 834d4afb5ceSopenharmony_ci if (n != lws_ptr_diff(p, start)) { 835d4afb5ceSopenharmony_ci lwsl_err("_write returned %d from %ld\n", n, 836d4afb5ceSopenharmony_ci (long)(p - start)); 837d4afb5ceSopenharmony_ci return -1; 838d4afb5ceSopenharmony_ci } 839d4afb5ceSopenharmony_ci 840d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 841d4afb5ceSopenharmony_ci 842d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 843d4afb5ceSopenharmony_ci return -1; 844d4afb5ceSopenharmony_ci 845d4afb5ceSopenharmony_ci return 0; 846d4afb5ceSopenharmony_ci } 847d4afb5ceSopenharmony_ci } 848d4afb5ceSopenharmony_ci 849d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG, 850d4afb5ceSopenharmony_ci (unsigned char *)sym, n, &p, end)) 851d4afb5ceSopenharmony_ci return -1; 852d4afb5ceSopenharmony_ci#endif 853d4afb5ceSopenharmony_ci 854d4afb5ceSopenharmony_ci mimetype = lws_get_mimetype(path, m); 855d4afb5ceSopenharmony_ci if (!mimetype) { 856d4afb5ceSopenharmony_ci lwsl_info("unknown mimetype for %s\n", path); 857d4afb5ceSopenharmony_ci if (lws_return_http_status(wsi, 858d4afb5ceSopenharmony_ci HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL) || 859d4afb5ceSopenharmony_ci lws_http_transaction_completed(wsi)) 860d4afb5ceSopenharmony_ci return -1; 861d4afb5ceSopenharmony_ci 862d4afb5ceSopenharmony_ci return 0; 863d4afb5ceSopenharmony_ci } 864d4afb5ceSopenharmony_ci if (!mimetype[0]) 865d4afb5ceSopenharmony_ci lwsl_debug("sending no mimetype for %s\n", path); 866d4afb5ceSopenharmony_ci 867d4afb5ceSopenharmony_ci wsi->sending_chunked = 0; 868d4afb5ceSopenharmony_ci wsi->interpreting = 0; 869d4afb5ceSopenharmony_ci 870d4afb5ceSopenharmony_ci /* 871d4afb5ceSopenharmony_ci * check if this is in the list of file suffixes to be interpreted by 872d4afb5ceSopenharmony_ci * a protocol 873d4afb5ceSopenharmony_ci */ 874d4afb5ceSopenharmony_ci while (pvo) { 875d4afb5ceSopenharmony_ci n = (int)strlen(path); 876d4afb5ceSopenharmony_ci if (n > (int)strlen(pvo->name) && 877d4afb5ceSopenharmony_ci !strcmp(&path[(unsigned int)n - strlen(pvo->name)], pvo->name)) { 878d4afb5ceSopenharmony_ci wsi->interpreting = 1; 879d4afb5ceSopenharmony_ci if (!wsi->mux_substream) 880d4afb5ceSopenharmony_ci wsi->sending_chunked = 1; 881d4afb5ceSopenharmony_ci 882d4afb5ceSopenharmony_ci wsi->protocol_interpret_idx = (char)( 883d4afb5ceSopenharmony_ci lws_vhost_name_to_protocol(wsi->a.vhost, 884d4afb5ceSopenharmony_ci pvo->value) - 885d4afb5ceSopenharmony_ci &lws_get_vhost(wsi)->protocols[0]); 886d4afb5ceSopenharmony_ci 887d4afb5ceSopenharmony_ci lwsl_debug("want %s interpreted by %s (pcol is %s)\n", path, 888d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[ 889d4afb5ceSopenharmony_ci (int)wsi->protocol_interpret_idx].name, 890d4afb5ceSopenharmony_ci wsi->a.protocol->name); 891d4afb5ceSopenharmony_ci if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[ 892d4afb5ceSopenharmony_ci (int)wsi->protocol_interpret_idx], __func__)) 893d4afb5ceSopenharmony_ci return -1; 894d4afb5ceSopenharmony_ci 895d4afb5ceSopenharmony_ci if (lws_ensure_user_space(wsi)) 896d4afb5ceSopenharmony_ci return -1; 897d4afb5ceSopenharmony_ci break; 898d4afb5ceSopenharmony_ci } 899d4afb5ceSopenharmony_ci pvo = pvo->next; 900d4afb5ceSopenharmony_ci } 901d4afb5ceSopenharmony_ci 902d4afb5ceSopenharmony_ci if (wsi->sending_chunked) { 903d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 904d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_TRANSFER_ENCODING, 905d4afb5ceSopenharmony_ci (unsigned char *)"chunked", 7, 906d4afb5ceSopenharmony_ci &p, end)) 907d4afb5ceSopenharmony_ci return -1; 908d4afb5ceSopenharmony_ci } 909d4afb5ceSopenharmony_ci 910d4afb5ceSopenharmony_ci if (m->protocol) { 911d4afb5ceSopenharmony_ci const struct lws_protocols *pp = lws_vhost_name_to_protocol( 912d4afb5ceSopenharmony_ci wsi->a.vhost, m->protocol); 913d4afb5ceSopenharmony_ci 914d4afb5ceSopenharmony_ci if (lws_bind_protocol(wsi, pp, __func__)) 915d4afb5ceSopenharmony_ci return -1; 916d4afb5ceSopenharmony_ci args.p = (char *)p; 917d4afb5ceSopenharmony_ci args.max_len = lws_ptr_diff(end, p); 918d4afb5ceSopenharmony_ci if (pp->callback(wsi, LWS_CALLBACK_ADD_HEADERS, 919d4afb5ceSopenharmony_ci wsi->user_space, &args, 0)) 920d4afb5ceSopenharmony_ci return -1; 921d4afb5ceSopenharmony_ci p = (unsigned char *)args.p; 922d4afb5ceSopenharmony_ci } 923d4afb5ceSopenharmony_ci 924d4afb5ceSopenharmony_ci *p = '\0'; 925d4afb5ceSopenharmony_ci n = lws_serve_http_file(wsi, path, mimetype, (char *)start, 926d4afb5ceSopenharmony_ci lws_ptr_diff(p, start)); 927d4afb5ceSopenharmony_ci 928d4afb5ceSopenharmony_ci if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi))) 929d4afb5ceSopenharmony_ci return -1; /* error or can't reuse connection: close the socket */ 930d4afb5ceSopenharmony_ci 931d4afb5ceSopenharmony_ci return 0; 932d4afb5ceSopenharmony_ci 933d4afb5ceSopenharmony_cinotfound: 934d4afb5ceSopenharmony_ci 935d4afb5ceSopenharmony_ci return 1; 936d4afb5ceSopenharmony_ci} 937d4afb5ceSopenharmony_ci#endif 938d4afb5ceSopenharmony_ci 939d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 940d4afb5ceSopenharmony_ciconst struct lws_http_mount * 941d4afb5ceSopenharmony_cilws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len) 942d4afb5ceSopenharmony_ci{ 943d4afb5ceSopenharmony_ci const struct lws_http_mount *hm, *hit = NULL; 944d4afb5ceSopenharmony_ci int best = 0; 945d4afb5ceSopenharmony_ci 946d4afb5ceSopenharmony_ci hm = wsi->a.vhost->http.mount_list; 947d4afb5ceSopenharmony_ci while (hm) { 948d4afb5ceSopenharmony_ci if (uri_len >= hm->mountpoint_len && 949d4afb5ceSopenharmony_ci !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len) && 950d4afb5ceSopenharmony_ci (uri_ptr[hm->mountpoint_len] == '\0' || 951d4afb5ceSopenharmony_ci uri_ptr[hm->mountpoint_len] == '/' || 952d4afb5ceSopenharmony_ci hm->mountpoint_len == 1) 953d4afb5ceSopenharmony_ci ) { 954d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) 955d4afb5ceSopenharmony_ci lws_metrics_tag_wsi_add(wsi, "mnt", hm->mountpoint); 956d4afb5ceSopenharmony_ci#endif 957d4afb5ceSopenharmony_ci 958d4afb5ceSopenharmony_ci if (hm->origin_protocol == LWSMPRO_CALLBACK || 959d4afb5ceSopenharmony_ci ((hm->origin_protocol == LWSMPRO_CGI || 960d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) || 961d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) || 962d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 963d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI) || 964d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) || 965d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_DELETE_URI) || 966d4afb5ceSopenharmony_ci#endif 967d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HEAD_URI) || 968d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 969d4afb5ceSopenharmony_ci (wsi->mux_substream && 970d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, 971d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_PATH)) || 972d4afb5ceSopenharmony_ci#endif 973d4afb5ceSopenharmony_ci hm->protocol) && 974d4afb5ceSopenharmony_ci hm->mountpoint_len > best)) { 975d4afb5ceSopenharmony_ci best = hm->mountpoint_len; 976d4afb5ceSopenharmony_ci hit = hm; 977d4afb5ceSopenharmony_ci } 978d4afb5ceSopenharmony_ci } 979d4afb5ceSopenharmony_ci hm = hm->mount_next; 980d4afb5ceSopenharmony_ci } 981d4afb5ceSopenharmony_ci 982d4afb5ceSopenharmony_ci return hit; 983d4afb5ceSopenharmony_ci} 984d4afb5ceSopenharmony_ci#endif 985d4afb5ceSopenharmony_ci 986d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_BASIC_AUTH) && !defined(LWS_PLAT_FREERTOS) && defined(LWS_WITH_FILE_OPS) 987d4afb5ceSopenharmony_cistatic int 988d4afb5ceSopenharmony_cilws_find_string_in_file(const char *filename, const char *string, int stringlen) 989d4afb5ceSopenharmony_ci{ 990d4afb5ceSopenharmony_ci char buf[128]; 991d4afb5ceSopenharmony_ci int fd, match = 0, pos = 0, n = 0, hit = 0; 992d4afb5ceSopenharmony_ci 993d4afb5ceSopenharmony_ci fd = lws_open(filename, O_RDONLY); 994d4afb5ceSopenharmony_ci if (fd < 0) { 995d4afb5ceSopenharmony_ci lwsl_err("can't open auth file: %s\n", filename); 996d4afb5ceSopenharmony_ci return 0; 997d4afb5ceSopenharmony_ci } 998d4afb5ceSopenharmony_ci 999d4afb5ceSopenharmony_ci while (1) { 1000d4afb5ceSopenharmony_ci if (pos == n) { 1001d4afb5ceSopenharmony_ci n = (int)read(fd, buf, sizeof(buf)); 1002d4afb5ceSopenharmony_ci if (n <= 0) { 1003d4afb5ceSopenharmony_ci if (match == stringlen) 1004d4afb5ceSopenharmony_ci hit = 1; 1005d4afb5ceSopenharmony_ci break; 1006d4afb5ceSopenharmony_ci } 1007d4afb5ceSopenharmony_ci pos = 0; 1008d4afb5ceSopenharmony_ci } 1009d4afb5ceSopenharmony_ci 1010d4afb5ceSopenharmony_ci if (match == stringlen) { 1011d4afb5ceSopenharmony_ci if (buf[pos] == '\r' || buf[pos] == '\n') { 1012d4afb5ceSopenharmony_ci hit = 1; 1013d4afb5ceSopenharmony_ci break; 1014d4afb5ceSopenharmony_ci } 1015d4afb5ceSopenharmony_ci match = 0; 1016d4afb5ceSopenharmony_ci } 1017d4afb5ceSopenharmony_ci 1018d4afb5ceSopenharmony_ci if (buf[pos] == string[match]) 1019d4afb5ceSopenharmony_ci match++; 1020d4afb5ceSopenharmony_ci else 1021d4afb5ceSopenharmony_ci match = 0; 1022d4afb5ceSopenharmony_ci 1023d4afb5ceSopenharmony_ci pos++; 1024d4afb5ceSopenharmony_ci } 1025d4afb5ceSopenharmony_ci 1026d4afb5ceSopenharmony_ci close(fd); 1027d4afb5ceSopenharmony_ci 1028d4afb5ceSopenharmony_ci return hit; 1029d4afb5ceSopenharmony_ci} 1030d4afb5ceSopenharmony_ci#endif 1031d4afb5ceSopenharmony_ci 1032d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_BASIC_AUTH) 1033d4afb5ceSopenharmony_ci 1034d4afb5ceSopenharmony_ciint 1035d4afb5ceSopenharmony_cilws_unauthorised_basic_auth(struct lws *wsi) 1036d4afb5ceSopenharmony_ci{ 1037d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 1038d4afb5ceSopenharmony_ci unsigned char *start = pt->serv_buf + LWS_PRE, 1039d4afb5ceSopenharmony_ci *p = start, *end = p + 2048; 1040d4afb5ceSopenharmony_ci char buf[64]; 1041d4afb5ceSopenharmony_ci int n; 1042d4afb5ceSopenharmony_ci 1043d4afb5ceSopenharmony_ci /* no auth... tell him it is required */ 1044d4afb5ceSopenharmony_ci 1045d4afb5ceSopenharmony_ci if (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, &p, end)) 1046d4afb5ceSopenharmony_ci return -1; 1047d4afb5ceSopenharmony_ci 1048d4afb5ceSopenharmony_ci n = lws_snprintf(buf, sizeof(buf), "Basic realm=\"lwsws\""); 1049d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 1050d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_WWW_AUTHENTICATE, 1051d4afb5ceSopenharmony_ci (unsigned char *)buf, n, &p, end)) 1052d4afb5ceSopenharmony_ci return -1; 1053d4afb5ceSopenharmony_ci 1054d4afb5ceSopenharmony_ci if (lws_add_http_header_content_length(wsi, 0, &p, end)) 1055d4afb5ceSopenharmony_ci return -1; 1056d4afb5ceSopenharmony_ci 1057d4afb5ceSopenharmony_ci if (lws_finalize_http_header(wsi, &p, end)) 1058d4afb5ceSopenharmony_ci return -1; 1059d4afb5ceSopenharmony_ci 1060d4afb5ceSopenharmony_ci n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_HTTP_HEADERS | 1061d4afb5ceSopenharmony_ci LWS_WRITE_H2_STREAM_END); 1062d4afb5ceSopenharmony_ci if (n < 0) 1063d4afb5ceSopenharmony_ci return -1; 1064d4afb5ceSopenharmony_ci 1065d4afb5ceSopenharmony_ci return lws_http_transaction_completed(wsi); 1066d4afb5ceSopenharmony_ci 1067d4afb5ceSopenharmony_ci} 1068d4afb5ceSopenharmony_ci 1069d4afb5ceSopenharmony_ci#endif 1070d4afb5ceSopenharmony_ci 1071d4afb5ceSopenharmony_ciint lws_clean_url(char *p) 1072d4afb5ceSopenharmony_ci{ 1073d4afb5ceSopenharmony_ci if (p[0] == 'h' && p[1] == 't' && p[2] == 't' && p[3] == 'p') { 1074d4afb5ceSopenharmony_ci p += 4; 1075d4afb5ceSopenharmony_ci if (*p == 's') 1076d4afb5ceSopenharmony_ci p++; 1077d4afb5ceSopenharmony_ci if (*p == ':') { 1078d4afb5ceSopenharmony_ci p++; 1079d4afb5ceSopenharmony_ci if (*p == '/') 1080d4afb5ceSopenharmony_ci p++; 1081d4afb5ceSopenharmony_ci } 1082d4afb5ceSopenharmony_ci } 1083d4afb5ceSopenharmony_ci 1084d4afb5ceSopenharmony_ci while (*p) { 1085d4afb5ceSopenharmony_ci if (p[0] == '/' && p[1] == '/') { 1086d4afb5ceSopenharmony_ci char *p1 = p; 1087d4afb5ceSopenharmony_ci while (*p1) { 1088d4afb5ceSopenharmony_ci *p1 = p1[1]; 1089d4afb5ceSopenharmony_ci p1++; 1090d4afb5ceSopenharmony_ci } 1091d4afb5ceSopenharmony_ci continue; 1092d4afb5ceSopenharmony_ci } 1093d4afb5ceSopenharmony_ci p++; 1094d4afb5ceSopenharmony_ci } 1095d4afb5ceSopenharmony_ci 1096d4afb5ceSopenharmony_ci return 0; 1097d4afb5ceSopenharmony_ci} 1098d4afb5ceSopenharmony_ci 1099d4afb5ceSopenharmony_cistatic const unsigned char methods[] = { 1100d4afb5ceSopenharmony_ci WSI_TOKEN_GET_URI, 1101d4afb5ceSopenharmony_ci WSI_TOKEN_POST_URI, 1102d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 1103d4afb5ceSopenharmony_ci WSI_TOKEN_OPTIONS_URI, 1104d4afb5ceSopenharmony_ci WSI_TOKEN_PUT_URI, 1105d4afb5ceSopenharmony_ci WSI_TOKEN_PATCH_URI, 1106d4afb5ceSopenharmony_ci WSI_TOKEN_DELETE_URI, 1107d4afb5ceSopenharmony_ci#endif 1108d4afb5ceSopenharmony_ci WSI_TOKEN_CONNECT, 1109d4afb5ceSopenharmony_ci WSI_TOKEN_HEAD_URI, 1110d4afb5ceSopenharmony_ci#ifdef LWS_WITH_HTTP2 1111d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_PATH, 1112d4afb5ceSopenharmony_ci#endif 1113d4afb5ceSopenharmony_ci}; 1114d4afb5ceSopenharmony_ci 1115d4afb5ceSopenharmony_ciint 1116d4afb5ceSopenharmony_cilws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len) 1117d4afb5ceSopenharmony_ci{ 1118d4afb5ceSopenharmony_ci int n, count = 0; 1119d4afb5ceSopenharmony_ci 1120d4afb5ceSopenharmony_ci for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++) 1121d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, methods[n])) 1122d4afb5ceSopenharmony_ci count++; 1123d4afb5ceSopenharmony_ci if (!count) { 1124d4afb5ceSopenharmony_ci lwsl_warn("Missing URI in HTTP request\n"); 1125d4afb5ceSopenharmony_ci return -1; 1126d4afb5ceSopenharmony_ci } 1127d4afb5ceSopenharmony_ci 1128d4afb5ceSopenharmony_ci if (count != 1 && 1129d4afb5ceSopenharmony_ci !((wsi->mux_substream || wsi->h2_stream_carries_ws) 1130d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 1131d4afb5ceSopenharmony_ci && 1132d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH) 1133d4afb5ceSopenharmony_ci#endif 1134d4afb5ceSopenharmony_ci )) { 1135d4afb5ceSopenharmony_ci lwsl_warn("multiple methods?\n"); 1136d4afb5ceSopenharmony_ci return -1; 1137d4afb5ceSopenharmony_ci } 1138d4afb5ceSopenharmony_ci 1139d4afb5ceSopenharmony_ci for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++) 1140d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, methods[n])) { 1141d4afb5ceSopenharmony_ci *puri_ptr = lws_hdr_simple_ptr(wsi, methods[n]); 1142d4afb5ceSopenharmony_ci *puri_len = lws_hdr_total_length(wsi, methods[n]); 1143d4afb5ceSopenharmony_ci return n; 1144d4afb5ceSopenharmony_ci } 1145d4afb5ceSopenharmony_ci 1146d4afb5ceSopenharmony_ci return -1; 1147d4afb5ceSopenharmony_ci} 1148d4afb5ceSopenharmony_ci 1149d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_BASIC_AUTH) 1150d4afb5ceSopenharmony_ci 1151d4afb5ceSopenharmony_cienum lws_check_basic_auth_results 1152d4afb5ceSopenharmony_cilws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file, 1153d4afb5ceSopenharmony_ci unsigned int auth_mode) 1154d4afb5ceSopenharmony_ci{ 1155d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 1156d4afb5ceSopenharmony_ci char b64[160], plain[(sizeof(b64) * 3) / 4], *pcolon; 1157d4afb5ceSopenharmony_ci int m, ml, fi, bar; 1158d4afb5ceSopenharmony_ci 1159d4afb5ceSopenharmony_ci if (!basic_auth_login_file && auth_mode == LWSAUTHM_DEFAULT) 1160d4afb5ceSopenharmony_ci return LCBA_CONTINUE; 1161d4afb5ceSopenharmony_ci 1162d4afb5ceSopenharmony_ci /* Did he send auth? */ 1163d4afb5ceSopenharmony_ci ml = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION); 1164d4afb5ceSopenharmony_ci if (!ml) 1165d4afb5ceSopenharmony_ci return LCBA_FAILED_AUTH; 1166d4afb5ceSopenharmony_ci 1167d4afb5ceSopenharmony_ci /* Disallow fragmentation monkey business */ 1168d4afb5ceSopenharmony_ci 1169d4afb5ceSopenharmony_ci fi = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_AUTHORIZATION]; 1170d4afb5ceSopenharmony_ci if (wsi->http.ah->frags[fi].nfrag) { 1171d4afb5ceSopenharmony_ci lwsl_err("fragmented basic auth header not allowed\n"); 1172d4afb5ceSopenharmony_ci return LCBA_FAILED_AUTH; 1173d4afb5ceSopenharmony_ci } 1174d4afb5ceSopenharmony_ci 1175d4afb5ceSopenharmony_ci m = lws_hdr_copy(wsi, b64, sizeof(b64), 1176d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_AUTHORIZATION); 1177d4afb5ceSopenharmony_ci if (m < 7) { 1178d4afb5ceSopenharmony_ci lwsl_err("b64 auth too long\n"); 1179d4afb5ceSopenharmony_ci return LCBA_END_TRANSACTION; 1180d4afb5ceSopenharmony_ci } 1181d4afb5ceSopenharmony_ci 1182d4afb5ceSopenharmony_ci b64[5] = '\0'; 1183d4afb5ceSopenharmony_ci if (strcasecmp(b64, "Basic")) { 1184d4afb5ceSopenharmony_ci lwsl_err("auth missing basic: %s\n", b64); 1185d4afb5ceSopenharmony_ci return LCBA_END_TRANSACTION; 1186d4afb5ceSopenharmony_ci } 1187d4afb5ceSopenharmony_ci 1188d4afb5ceSopenharmony_ci /* It'll be like Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l */ 1189d4afb5ceSopenharmony_ci 1190d4afb5ceSopenharmony_ci m = lws_b64_decode_string(b64 + 6, plain, sizeof(plain) - 1); 1191d4afb5ceSopenharmony_ci if (m < 0) { 1192d4afb5ceSopenharmony_ci lwsl_err("plain auth too long\n"); 1193d4afb5ceSopenharmony_ci return LCBA_END_TRANSACTION; 1194d4afb5ceSopenharmony_ci } 1195d4afb5ceSopenharmony_ci 1196d4afb5ceSopenharmony_ci plain[m] = '\0'; 1197d4afb5ceSopenharmony_ci pcolon = strchr(plain, ':'); 1198d4afb5ceSopenharmony_ci if (!pcolon) { 1199d4afb5ceSopenharmony_ci lwsl_err("basic auth format broken\n"); 1200d4afb5ceSopenharmony_ci return LCBA_END_TRANSACTION; 1201d4afb5ceSopenharmony_ci } 1202d4afb5ceSopenharmony_ci 1203d4afb5ceSopenharmony_ci switch (auth_mode) { 1204d4afb5ceSopenharmony_ci case LWSAUTHM_DEFAULT: 1205d4afb5ceSopenharmony_ci if (lws_find_string_in_file(basic_auth_login_file, plain, m)) 1206d4afb5ceSopenharmony_ci break; 1207d4afb5ceSopenharmony_ci lwsl_err("%s: basic auth lookup failed\n", __func__); 1208d4afb5ceSopenharmony_ci return LCBA_FAILED_AUTH; 1209d4afb5ceSopenharmony_ci 1210d4afb5ceSopenharmony_ci case LWSAUTHM_BASIC_AUTH_CALLBACK: 1211d4afb5ceSopenharmony_ci bar = wsi->a.protocol->callback(wsi, 1212d4afb5ceSopenharmony_ci LWS_CALLBACK_VERIFY_BASIC_AUTHORIZATION, 1213d4afb5ceSopenharmony_ci wsi->user_space, plain, (unsigned int)m); 1214d4afb5ceSopenharmony_ci if (!bar) 1215d4afb5ceSopenharmony_ci return LCBA_FAILED_AUTH; 1216d4afb5ceSopenharmony_ci break; 1217d4afb5ceSopenharmony_ci default: 1218d4afb5ceSopenharmony_ci /* Invalid auth mode so lets fail all authentication attempts */ 1219d4afb5ceSopenharmony_ci return LCBA_FAILED_AUTH; 1220d4afb5ceSopenharmony_ci } 1221d4afb5ceSopenharmony_ci 1222d4afb5ceSopenharmony_ci /* 1223d4afb5ceSopenharmony_ci * Rewrite WSI_TOKEN_HTTP_AUTHORIZATION so it is just the 1224d4afb5ceSopenharmony_ci * authorized username 1225d4afb5ceSopenharmony_ci */ 1226d4afb5ceSopenharmony_ci 1227d4afb5ceSopenharmony_ci *pcolon = '\0'; 1228d4afb5ceSopenharmony_ci wsi->http.ah->frags[fi].len = (uint16_t)lws_ptr_diff_size_t(pcolon, &plain[0]); 1229d4afb5ceSopenharmony_ci pcolon = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_AUTHORIZATION); 1230d4afb5ceSopenharmony_ci strncpy(pcolon, plain, (unsigned int)(ml - 1)); 1231d4afb5ceSopenharmony_ci pcolon[ml - 1] = '\0'; 1232d4afb5ceSopenharmony_ci lwsl_info("%s: basic auth accepted for %s\n", __func__, 1233d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_AUTHORIZATION)); 1234d4afb5ceSopenharmony_ci 1235d4afb5ceSopenharmony_ci return LCBA_CONTINUE; 1236d4afb5ceSopenharmony_ci#else 1237d4afb5ceSopenharmony_ci if (!basic_auth_login_file && auth_mode == LWSAUTHM_DEFAULT) 1238d4afb5ceSopenharmony_ci return LCBA_CONTINUE; 1239d4afb5ceSopenharmony_ci return LCBA_FAILED_AUTH; 1240d4afb5ceSopenharmony_ci#endif 1241d4afb5ceSopenharmony_ci} 1242d4afb5ceSopenharmony_ci 1243d4afb5ceSopenharmony_ci#endif 1244d4afb5ceSopenharmony_ci 1245d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 1246d4afb5ceSopenharmony_ci/* 1247d4afb5ceSopenharmony_ci * Set up an onward http proxy connection according to the mount this 1248d4afb5ceSopenharmony_ci * uri falls under. Notice this can also be starting the proxying of what was 1249d4afb5ceSopenharmony_ci * originally an incoming h1 upgrade, or an h2 ws "upgrade". 1250d4afb5ceSopenharmony_ci */ 1251d4afb5ceSopenharmony_ciint 1252d4afb5ceSopenharmony_cilws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit, 1253d4afb5ceSopenharmony_ci char *uri_ptr, char ws) 1254d4afb5ceSopenharmony_ci{ 1255d4afb5ceSopenharmony_ci char ads[96], host[96], *pcolon, *pslash, unix_skt = 0; 1256d4afb5ceSopenharmony_ci struct lws_client_connect_info i; 1257d4afb5ceSopenharmony_ci struct lws *cwsi; 1258d4afb5ceSopenharmony_ci int n, na; 1259d4afb5ceSopenharmony_ci unsigned int max_http_header_data = wsi->a.context->max_http_header_data > 256 ? 1260d4afb5ceSopenharmony_ci wsi->a.context->max_http_header_data : 256; 1261d4afb5ceSopenharmony_ci char *rpath = NULL; 1262d4afb5ceSopenharmony_ci 1263d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) 1264d4afb5ceSopenharmony_ci if (ws) 1265d4afb5ceSopenharmony_ci /* 1266d4afb5ceSopenharmony_ci * Neither our inbound ws upgrade request side, nor our onward 1267d4afb5ceSopenharmony_ci * ws client connection on our side can bind to the actual 1268d4afb5ceSopenharmony_ci * protocol that only the remote inbound side and the remote 1269d4afb5ceSopenharmony_ci * onward side understand. 1270d4afb5ceSopenharmony_ci * 1271d4afb5ceSopenharmony_ci * Instead these are both bound to our built-in "lws-ws-proxy" 1272d4afb5ceSopenharmony_ci * protocol, which understands how to proxy between the two 1273d4afb5ceSopenharmony_ci * sides. 1274d4afb5ceSopenharmony_ci * 1275d4afb5ceSopenharmony_ci * We bind the parent, inbound part here and our side of the 1276d4afb5ceSopenharmony_ci * onward client connection is bound to the same handler using 1277d4afb5ceSopenharmony_ci * the .local_protocol_name. 1278d4afb5ceSopenharmony_ci */ 1279d4afb5ceSopenharmony_ci lws_bind_protocol(wsi, &lws_ws_proxy, __func__); 1280d4afb5ceSopenharmony_ci#endif 1281d4afb5ceSopenharmony_ci memset(&i, 0, sizeof(i)); 1282d4afb5ceSopenharmony_ci i.context = lws_get_context(wsi); 1283d4afb5ceSopenharmony_ci 1284d4afb5ceSopenharmony_ci if (hit->origin[0] == '+') 1285d4afb5ceSopenharmony_ci unix_skt = 1; 1286d4afb5ceSopenharmony_ci 1287d4afb5ceSopenharmony_ci pcolon = strchr(hit->origin, ':'); 1288d4afb5ceSopenharmony_ci pslash = strchr(hit->origin, '/'); 1289d4afb5ceSopenharmony_ci if (!pslash) { 1290d4afb5ceSopenharmony_ci lwsl_err("Proxy mount origin '%s' must have /\n", hit->origin); 1291d4afb5ceSopenharmony_ci return -1; 1292d4afb5ceSopenharmony_ci } 1293d4afb5ceSopenharmony_ci 1294d4afb5ceSopenharmony_ci if (unix_skt) { 1295d4afb5ceSopenharmony_ci if (!pcolon) { 1296d4afb5ceSopenharmony_ci lwsl_err("Proxy mount origin for unix skt must " 1297d4afb5ceSopenharmony_ci "have address delimited by :\n"); 1298d4afb5ceSopenharmony_ci 1299d4afb5ceSopenharmony_ci return -1; 1300d4afb5ceSopenharmony_ci } 1301d4afb5ceSopenharmony_ci n = lws_ptr_diff(pcolon, hit->origin); 1302d4afb5ceSopenharmony_ci pslash = pcolon; 1303d4afb5ceSopenharmony_ci } else { 1304d4afb5ceSopenharmony_ci if (pcolon > pslash) 1305d4afb5ceSopenharmony_ci pcolon = NULL; 1306d4afb5ceSopenharmony_ci 1307d4afb5ceSopenharmony_ci if (pcolon) 1308d4afb5ceSopenharmony_ci n = (int)(pcolon - hit->origin); 1309d4afb5ceSopenharmony_ci else 1310d4afb5ceSopenharmony_ci n = (int)(pslash - hit->origin); 1311d4afb5ceSopenharmony_ci 1312d4afb5ceSopenharmony_ci if (n >= (int)sizeof(ads) - 2) 1313d4afb5ceSopenharmony_ci n = sizeof(ads) - 2; 1314d4afb5ceSopenharmony_ci } 1315d4afb5ceSopenharmony_ci 1316d4afb5ceSopenharmony_ci memcpy(ads, hit->origin, (unsigned int)n); 1317d4afb5ceSopenharmony_ci ads[n] = '\0'; 1318d4afb5ceSopenharmony_ci 1319d4afb5ceSopenharmony_ci i.address = ads; 1320d4afb5ceSopenharmony_ci i.port = 80; 1321d4afb5ceSopenharmony_ci if (hit->origin_protocol == LWSMPRO_HTTPS) { 1322d4afb5ceSopenharmony_ci i.port = 443; 1323d4afb5ceSopenharmony_ci i.ssl_connection = 1; 1324d4afb5ceSopenharmony_ci } 1325d4afb5ceSopenharmony_ci if (pcolon) 1326d4afb5ceSopenharmony_ci i.port = atoi(pcolon + 1); 1327d4afb5ceSopenharmony_ci 1328d4afb5ceSopenharmony_ci rpath = lws_malloc(max_http_header_data, __func__); 1329d4afb5ceSopenharmony_ci if (!rpath) 1330d4afb5ceSopenharmony_ci return -1; 1331d4afb5ceSopenharmony_ci 1332d4afb5ceSopenharmony_ci /* rpath needs cleaning after this... ---> */ 1333d4afb5ceSopenharmony_ci 1334d4afb5ceSopenharmony_ci n = lws_snprintf(rpath, max_http_header_data - 1, "/%s/%s", 1335d4afb5ceSopenharmony_ci pslash + 1, uri_ptr + hit->mountpoint_len) - 1; 1336d4afb5ceSopenharmony_ci lws_clean_url(rpath); 1337d4afb5ceSopenharmony_ci n = (int)strlen(rpath); 1338d4afb5ceSopenharmony_ci if (n && rpath[n - 1] == '/') 1339d4afb5ceSopenharmony_ci n--; 1340d4afb5ceSopenharmony_ci 1341d4afb5ceSopenharmony_ci na = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS); 1342d4afb5ceSopenharmony_ci if (na) { 1343d4afb5ceSopenharmony_ci char *p; 1344d4afb5ceSopenharmony_ci int budg; 1345d4afb5ceSopenharmony_ci 1346d4afb5ceSopenharmony_ci if (!n) /* don't start with the ?... use the first / if so */ 1347d4afb5ceSopenharmony_ci n++; 1348d4afb5ceSopenharmony_ci 1349d4afb5ceSopenharmony_ci p = rpath + n; 1350d4afb5ceSopenharmony_ci 1351d4afb5ceSopenharmony_ci if (na >= (int)max_http_header_data - n - 2) { 1352d4afb5ceSopenharmony_ci lwsl_info("%s: query string %d longer " 1353d4afb5ceSopenharmony_ci "than we can handle\n", __func__, 1354d4afb5ceSopenharmony_ci na); 1355d4afb5ceSopenharmony_ci lws_free(rpath); 1356d4afb5ceSopenharmony_ci return -1; 1357d4afb5ceSopenharmony_ci } 1358d4afb5ceSopenharmony_ci 1359d4afb5ceSopenharmony_ci *p++ = '?'; 1360d4afb5ceSopenharmony_ci budg = lws_hdr_copy(wsi, p, 1361d4afb5ceSopenharmony_ci (int)(&rpath[max_http_header_data - 1] - p), 1362d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_URI_ARGS); 1363d4afb5ceSopenharmony_ci if (budg > 0) 1364d4afb5ceSopenharmony_ci p += budg; 1365d4afb5ceSopenharmony_ci 1366d4afb5ceSopenharmony_ci *p = '\0'; 1367d4afb5ceSopenharmony_ci } 1368d4afb5ceSopenharmony_ci 1369d4afb5ceSopenharmony_ci i.path = rpath; 1370d4afb5ceSopenharmony_ci lwsl_notice("%s: proxied path '%s'\n", __func__, i.path); 1371d4afb5ceSopenharmony_ci 1372d4afb5ceSopenharmony_ci /* incoming may be h1 or h2... if he sends h1 HOST, use that 1373d4afb5ceSopenharmony_ci * directly, otherwise we must convert h2 :authority to h1 1374d4afb5ceSopenharmony_ci * host */ 1375d4afb5ceSopenharmony_ci 1376d4afb5ceSopenharmony_ci i.host = NULL; 1377d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 1378d4afb5ceSopenharmony_ci n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY); 1379d4afb5ceSopenharmony_ci if (n > 0) 1380d4afb5ceSopenharmony_ci i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY); 1381d4afb5ceSopenharmony_ci else 1382d4afb5ceSopenharmony_ci#endif 1383d4afb5ceSopenharmony_ci { 1384d4afb5ceSopenharmony_ci n = lws_hdr_total_length(wsi, WSI_TOKEN_HOST); 1385d4afb5ceSopenharmony_ci if (n > 0) 1386d4afb5ceSopenharmony_ci i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST); 1387d4afb5ceSopenharmony_ci } 1388d4afb5ceSopenharmony_ci 1389d4afb5ceSopenharmony_ci#if 0 1390d4afb5ceSopenharmony_ci if (i.address[0] != '+' || 1391d4afb5ceSopenharmony_ci !lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)) 1392d4afb5ceSopenharmony_ci i.host = i.address; 1393d4afb5ceSopenharmony_ci else 1394d4afb5ceSopenharmony_ci i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST); 1395d4afb5ceSopenharmony_ci#endif 1396d4afb5ceSopenharmony_ci i.origin = NULL; 1397d4afb5ceSopenharmony_ci if (!ws) { 1398d4afb5ceSopenharmony_ci if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI) 1399d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 1400d4afb5ceSopenharmony_ci || ( 1401d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) && 1402d4afb5ceSopenharmony_ci !strcmp(lws_hdr_simple_ptr(wsi, 1403d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_METHOD), "post") 1404d4afb5ceSopenharmony_ci ) 1405d4afb5ceSopenharmony_ci#endif 1406d4afb5ceSopenharmony_ci ) 1407d4afb5ceSopenharmony_ci i.method = "POST"; 1408d4afb5ceSopenharmony_ci else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PUT_URI) 1409d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 1410d4afb5ceSopenharmony_ci || ( 1411d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) && 1412d4afb5ceSopenharmony_ci !strcmp(lws_hdr_simple_ptr(wsi, 1413d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_METHOD), "put") 1414d4afb5ceSopenharmony_ci ) 1415d4afb5ceSopenharmony_ci#endif 1416d4afb5ceSopenharmony_ci ) 1417d4afb5ceSopenharmony_ci i.method = "PUT"; 1418d4afb5ceSopenharmony_ci else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PATCH_URI) 1419d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 1420d4afb5ceSopenharmony_ci || ( 1421d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) && 1422d4afb5ceSopenharmony_ci !strcmp(lws_hdr_simple_ptr(wsi, 1423d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_METHOD), "patch") 1424d4afb5ceSopenharmony_ci ) 1425d4afb5ceSopenharmony_ci#endif 1426d4afb5ceSopenharmony_ci ) 1427d4afb5ceSopenharmony_ci i.method = "PATCH"; 1428d4afb5ceSopenharmony_ci else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_DELETE_URI) 1429d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 1430d4afb5ceSopenharmony_ci || ( 1431d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) && 1432d4afb5ceSopenharmony_ci !strcmp(lws_hdr_simple_ptr(wsi, 1433d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_METHOD), "delete") 1434d4afb5ceSopenharmony_ci ) 1435d4afb5ceSopenharmony_ci#endif 1436d4afb5ceSopenharmony_ci ) 1437d4afb5ceSopenharmony_ci i.method = "DELETE"; 1438d4afb5ceSopenharmony_ci else 1439d4afb5ceSopenharmony_ci i.method = "GET"; 1440d4afb5ceSopenharmony_ci } 1441d4afb5ceSopenharmony_ci 1442d4afb5ceSopenharmony_ci if (i.host) 1443d4afb5ceSopenharmony_ci lws_snprintf(host, sizeof(host), "%s:%u", i.host, 1444d4afb5ceSopenharmony_ci wsi->a.vhost->listen_port); 1445d4afb5ceSopenharmony_ci else 1446d4afb5ceSopenharmony_ci lws_snprintf(host, sizeof(host), "%s:%d", i.address, i.port); 1447d4afb5ceSopenharmony_ci 1448d4afb5ceSopenharmony_ci i.host = host; 1449d4afb5ceSopenharmony_ci 1450d4afb5ceSopenharmony_ci i.alpn = "http/1.1"; 1451d4afb5ceSopenharmony_ci i.parent_wsi = wsi; 1452d4afb5ceSopenharmony_ci i.pwsi = &cwsi; 1453d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) 1454d4afb5ceSopenharmony_ci i.protocol = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL); 1455d4afb5ceSopenharmony_ci if (ws) 1456d4afb5ceSopenharmony_ci i.local_protocol_name = "lws-ws-proxy"; 1457d4afb5ceSopenharmony_ci#endif 1458d4afb5ceSopenharmony_ci 1459d4afb5ceSopenharmony_ci// i.uri_replace_from = hit->origin; 1460d4afb5ceSopenharmony_ci// i.uri_replace_to = hit->mountpoint; 1461d4afb5ceSopenharmony_ci 1462d4afb5ceSopenharmony_ci lwsl_info("proxying to %s port %d url %s, ssl %d, from %s, to %s\n", 1463d4afb5ceSopenharmony_ci i.address, i.port, i.path, i.ssl_connection, 1464d4afb5ceSopenharmony_ci i.uri_replace_from, i.uri_replace_to); 1465d4afb5ceSopenharmony_ci 1466d4afb5ceSopenharmony_ci if (!lws_client_connect_via_info(&i)) { 1467d4afb5ceSopenharmony_ci lwsl_err("proxy connect fail\n"); 1468d4afb5ceSopenharmony_ci 1469d4afb5ceSopenharmony_ci /* 1470d4afb5ceSopenharmony_ci * ... we can't do the proxy action, but we can 1471d4afb5ceSopenharmony_ci * cleanly return him a 503 and a description 1472d4afb5ceSopenharmony_ci */ 1473d4afb5ceSopenharmony_ci 1474d4afb5ceSopenharmony_ci lws_return_http_status(wsi, 1475d4afb5ceSopenharmony_ci HTTP_STATUS_SERVICE_UNAVAILABLE, 1476d4afb5ceSopenharmony_ci "<h1>Service Temporarily Unavailable</h1>" 1477d4afb5ceSopenharmony_ci "The server is temporarily unable to service " 1478d4afb5ceSopenharmony_ci "your request due to maintenance downtime or " 1479d4afb5ceSopenharmony_ci "capacity problems. Please try again later."); 1480d4afb5ceSopenharmony_ci lws_free(rpath); 1481d4afb5ceSopenharmony_ci return 1; 1482d4afb5ceSopenharmony_ci } 1483d4afb5ceSopenharmony_ci lws_free(rpath); 1484d4afb5ceSopenharmony_ci 1485d4afb5ceSopenharmony_ci lwsl_info("%s: setting proxy clientside on %s (parent %s)\n", 1486d4afb5ceSopenharmony_ci __func__, lws_wsi_tag(cwsi), lws_wsi_tag(lws_get_parent(cwsi))); 1487d4afb5ceSopenharmony_ci 1488d4afb5ceSopenharmony_ci cwsi->http.proxy_clientside = 1; 1489d4afb5ceSopenharmony_ci if (ws) { 1490d4afb5ceSopenharmony_ci wsi->proxied_ws_parent = 1; 1491d4afb5ceSopenharmony_ci cwsi->h1_ws_proxied = 1; 1492d4afb5ceSopenharmony_ci if (i.protocol) { 1493d4afb5ceSopenharmony_ci lwsl_debug("%s: (requesting '%s')\n", 1494d4afb5ceSopenharmony_ci __func__, i.protocol); 1495d4afb5ceSopenharmony_ci } 1496d4afb5ceSopenharmony_ci } 1497d4afb5ceSopenharmony_ci 1498d4afb5ceSopenharmony_ci return 0; 1499d4afb5ceSopenharmony_ci} 1500d4afb5ceSopenharmony_ci#endif 1501d4afb5ceSopenharmony_ci 1502d4afb5ceSopenharmony_ci 1503d4afb5ceSopenharmony_cistatic const char * const oprot[] = { 1504d4afb5ceSopenharmony_ci "http://", "https://" 1505d4afb5ceSopenharmony_ci}; 1506d4afb5ceSopenharmony_ci 1507d4afb5ceSopenharmony_ci 1508d4afb5ceSopenharmony_cistatic int 1509d4afb5ceSopenharmony_cilws_http_redirect_hit(struct lws_context_per_thread *pt, struct lws *wsi, 1510d4afb5ceSopenharmony_ci const struct lws_http_mount *hit, char *uri_ptr, 1511d4afb5ceSopenharmony_ci int uri_len, int *h) 1512d4afb5ceSopenharmony_ci{ 1513d4afb5ceSopenharmony_ci char *s; 1514d4afb5ceSopenharmony_ci int n; 1515d4afb5ceSopenharmony_ci 1516d4afb5ceSopenharmony_ci *h = 0; 1517d4afb5ceSopenharmony_ci s = uri_ptr + hit->mountpoint_len; 1518d4afb5ceSopenharmony_ci 1519d4afb5ceSopenharmony_ci /* 1520d4afb5ceSopenharmony_ci * if we have a mountpoint like https://xxx.com/yyy 1521d4afb5ceSopenharmony_ci * there is an implied / at the end for our purposes since 1522d4afb5ceSopenharmony_ci * we can only mount on a "directory". 1523d4afb5ceSopenharmony_ci * 1524d4afb5ceSopenharmony_ci * But if we just go with that, the browser cannot understand 1525d4afb5ceSopenharmony_ci * that he is actually looking down one "directory level", so 1526d4afb5ceSopenharmony_ci * even though we give him /yyy/abc.html he acts like the 1527d4afb5ceSopenharmony_ci * current directory level is /. So relative urls like "x.png" 1528d4afb5ceSopenharmony_ci * wrongly look outside the mountpoint. 1529d4afb5ceSopenharmony_ci * 1530d4afb5ceSopenharmony_ci * Therefore if we didn't come in on a url with an explicit 1531d4afb5ceSopenharmony_ci * / at the end, we must redirect to add it so the browser 1532d4afb5ceSopenharmony_ci * understands he is one "directory level" down. 1533d4afb5ceSopenharmony_ci */ 1534d4afb5ceSopenharmony_ci if ((hit->mountpoint_len > 1 || 1535d4afb5ceSopenharmony_ci (hit->origin_protocol == LWSMPRO_REDIR_HTTP || 1536d4afb5ceSopenharmony_ci hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) && 1537d4afb5ceSopenharmony_ci (*s != '/' || 1538d4afb5ceSopenharmony_ci (hit->origin_protocol == LWSMPRO_REDIR_HTTP || 1539d4afb5ceSopenharmony_ci hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) && 1540d4afb5ceSopenharmony_ci (hit->origin_protocol != LWSMPRO_CGI && 1541d4afb5ceSopenharmony_ci hit->origin_protocol != LWSMPRO_CALLBACK)) { 1542d4afb5ceSopenharmony_ci unsigned char *start = pt->serv_buf + LWS_PRE, *p = start, 1543d4afb5ceSopenharmony_ci *end = p + wsi->a.context->pt_serv_buf_size - 1544d4afb5ceSopenharmony_ci LWS_PRE - 512; 1545d4afb5ceSopenharmony_ci 1546d4afb5ceSopenharmony_ci *h = 1; 1547d4afb5ceSopenharmony_ci 1548d4afb5ceSopenharmony_ci lwsl_info("Doing 301 '%s' org %s\n", s, hit->origin); 1549d4afb5ceSopenharmony_ci 1550d4afb5ceSopenharmony_ci /* > at start indicates deal with by redirect */ 1551d4afb5ceSopenharmony_ci if (hit->origin_protocol == LWSMPRO_REDIR_HTTP || 1552d4afb5ceSopenharmony_ci hit->origin_protocol == LWSMPRO_REDIR_HTTPS) 1553d4afb5ceSopenharmony_ci n = lws_snprintf((char *)end, 256, "%s%s", 1554d4afb5ceSopenharmony_ci oprot[hit->origin_protocol & 1], 1555d4afb5ceSopenharmony_ci hit->origin); 1556d4afb5ceSopenharmony_ci else { 1557d4afb5ceSopenharmony_ci if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { 1558d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 1559d4afb5ceSopenharmony_ci if (!lws_hdr_total_length(wsi, 1560d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_AUTHORITY)) 1561d4afb5ceSopenharmony_ci#endif 1562d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1563d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 1564d4afb5ceSopenharmony_ci n = lws_snprintf((char *)end, 256, 1565d4afb5ceSopenharmony_ci "%s%s%s/", oprot[!!lws_is_ssl(wsi)], 1566d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, 1567d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_AUTHORITY), 1568d4afb5ceSopenharmony_ci uri_ptr); 1569d4afb5ceSopenharmony_ci#else 1570d4afb5ceSopenharmony_ci ; 1571d4afb5ceSopenharmony_ci#endif 1572d4afb5ceSopenharmony_ci } else 1573d4afb5ceSopenharmony_ci n = lws_snprintf((char *)end, 256, 1574d4afb5ceSopenharmony_ci "%s%s%s/", oprot[!!lws_is_ssl(wsi)], 1575d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST), 1576d4afb5ceSopenharmony_ci uri_ptr); 1577d4afb5ceSopenharmony_ci } 1578d4afb5ceSopenharmony_ci 1579d4afb5ceSopenharmony_ci lws_clean_url((char *)end); 1580d4afb5ceSopenharmony_ci n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY, 1581d4afb5ceSopenharmony_ci end, n, &p, end); 1582d4afb5ceSopenharmony_ci if ((int)n < 0) 1583d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1584d4afb5ceSopenharmony_ci 1585d4afb5ceSopenharmony_ci return lws_http_transaction_completed(wsi); 1586d4afb5ceSopenharmony_ci } 1587d4afb5ceSopenharmony_ci 1588d4afb5ceSopenharmony_ci return 0; 1589d4afb5ceSopenharmony_ci 1590d4afb5ceSopenharmony_cibail_nuke_ah: 1591d4afb5ceSopenharmony_ci lws_header_table_detach(wsi, 1); 1592d4afb5ceSopenharmony_ci 1593d4afb5ceSopenharmony_ci return 1; 1594d4afb5ceSopenharmony_ci} 1595d4afb5ceSopenharmony_ci 1596d4afb5ceSopenharmony_ciint 1597d4afb5ceSopenharmony_cilws_http_action(struct lws *wsi) 1598d4afb5ceSopenharmony_ci{ 1599d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 1600d4afb5ceSopenharmony_ci int uri_len = 0, meth, m, http_version_len, ha; 1601d4afb5ceSopenharmony_ci const struct lws_http_mount *hit = NULL; 1602d4afb5ceSopenharmony_ci enum http_version request_version; 1603d4afb5ceSopenharmony_ci struct lws_process_html_args args; 1604d4afb5ceSopenharmony_ci enum http_conn_type conn_type; 1605d4afb5ceSopenharmony_ci char content_length_str[32]; 1606d4afb5ceSopenharmony_ci char http_version_str[12]; 1607d4afb5ceSopenharmony_ci char http_conn_str[25]; 1608d4afb5ceSopenharmony_ci char *uri_ptr = NULL; 1609d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 1610d4afb5ceSopenharmony_ci char *s; 1611d4afb5ceSopenharmony_ci#endif 1612d4afb5ceSopenharmony_ci unsigned int n; 1613d4afb5ceSopenharmony_ci 1614d4afb5ceSopenharmony_ci meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len); 1615d4afb5ceSopenharmony_ci if (meth < 0 || meth >= (int)LWS_ARRAY_SIZE(method_names)) 1616d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1617d4afb5ceSopenharmony_ci 1618d4afb5ceSopenharmony_ci lws_metrics_tag_wsi_add(wsi, "vh", wsi->a.vhost->name); 1619d4afb5ceSopenharmony_ci lws_metrics_tag_wsi_add(wsi, "meth", method_names[meth]); 1620d4afb5ceSopenharmony_ci 1621d4afb5ceSopenharmony_ci /* we insist on absolute paths */ 1622d4afb5ceSopenharmony_ci 1623d4afb5ceSopenharmony_ci if (!uri_ptr || uri_ptr[0] != '/') { 1624d4afb5ceSopenharmony_ci lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL); 1625d4afb5ceSopenharmony_ci 1626d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1627d4afb5ceSopenharmony_ci } 1628d4afb5ceSopenharmony_ci 1629d4afb5ceSopenharmony_ci lwsl_info("Method: '%s' (%d), request for '%s'\n", method_names[meth], 1630d4afb5ceSopenharmony_ci meth, uri_ptr); 1631d4afb5ceSopenharmony_ci 1632d4afb5ceSopenharmony_ci if (wsi->role_ops && 1633d4afb5ceSopenharmony_ci lws_rops_fidx(wsi->role_ops, LWS_ROPS_check_upgrades)) 1634d4afb5ceSopenharmony_ci switch (lws_rops_func_fidx(wsi->role_ops, 1635d4afb5ceSopenharmony_ci LWS_ROPS_check_upgrades). 1636d4afb5ceSopenharmony_ci check_upgrades(wsi)) { 1637d4afb5ceSopenharmony_ci case LWS_UPG_RET_DONE: 1638d4afb5ceSopenharmony_ci return 0; 1639d4afb5ceSopenharmony_ci case LWS_UPG_RET_CONTINUE: 1640d4afb5ceSopenharmony_ci break; 1641d4afb5ceSopenharmony_ci case LWS_UPG_RET_BAIL: 1642d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1643d4afb5ceSopenharmony_ci } 1644d4afb5ceSopenharmony_ci 1645d4afb5ceSopenharmony_ci if (lws_ensure_user_space(wsi)) 1646d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1647d4afb5ceSopenharmony_ci 1648d4afb5ceSopenharmony_ci /* HTTP header had a content length? */ 1649d4afb5ceSopenharmony_ci 1650d4afb5ceSopenharmony_ci wsi->http.rx_content_length = 0; 1651d4afb5ceSopenharmony_ci wsi->http.content_length_explicitly_zero = 0; 1652d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) 1653d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 1654d4afb5ceSopenharmony_ci || 1655d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) || 1656d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI) 1657d4afb5ceSopenharmony_ci#endif 1658d4afb5ceSopenharmony_ci ) 1659d4afb5ceSopenharmony_ci wsi->http.rx_content_length = 100 * 1024 * 1024; 1660d4afb5ceSopenharmony_ci 1661d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) && 1662d4afb5ceSopenharmony_ci lws_hdr_copy(wsi, content_length_str, 1663d4afb5ceSopenharmony_ci sizeof(content_length_str) - 1, 1664d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_LENGTH) > 0) { 1665d4afb5ceSopenharmony_ci wsi->http.rx_content_remain = wsi->http.rx_content_length = 1666d4afb5ceSopenharmony_ci (lws_filepos_t)atoll(content_length_str); 1667d4afb5ceSopenharmony_ci if (!wsi->http.rx_content_length) { 1668d4afb5ceSopenharmony_ci wsi->http.content_length_explicitly_zero = 1; 1669d4afb5ceSopenharmony_ci lwsl_debug("%s: explicit 0 content-length\n", __func__); 1670d4afb5ceSopenharmony_ci } 1671d4afb5ceSopenharmony_ci } 1672d4afb5ceSopenharmony_ci 1673d4afb5ceSopenharmony_ci if (wsi->mux_substream) { 1674d4afb5ceSopenharmony_ci wsi->http.request_version = HTTP_VERSION_2; 1675d4afb5ceSopenharmony_ci } else { 1676d4afb5ceSopenharmony_ci /* http_version? Default to 1.0, override with token: */ 1677d4afb5ceSopenharmony_ci request_version = HTTP_VERSION_1_0; 1678d4afb5ceSopenharmony_ci 1679d4afb5ceSopenharmony_ci /* Works for single digit HTTP versions. : */ 1680d4afb5ceSopenharmony_ci http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP); 1681d4afb5ceSopenharmony_ci if (http_version_len > 7 && 1682d4afb5ceSopenharmony_ci lws_hdr_copy(wsi, http_version_str, 1683d4afb5ceSopenharmony_ci sizeof(http_version_str) - 1, 1684d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP) > 0 && 1685d4afb5ceSopenharmony_ci http_version_str[5] == '1' && http_version_str[7] == '1') 1686d4afb5ceSopenharmony_ci request_version = HTTP_VERSION_1_1; 1687d4afb5ceSopenharmony_ci 1688d4afb5ceSopenharmony_ci wsi->http.request_version = request_version; 1689d4afb5ceSopenharmony_ci 1690d4afb5ceSopenharmony_ci /* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */ 1691d4afb5ceSopenharmony_ci if (request_version == HTTP_VERSION_1_1) 1692d4afb5ceSopenharmony_ci conn_type = HTTP_CONNECTION_KEEP_ALIVE; 1693d4afb5ceSopenharmony_ci else 1694d4afb5ceSopenharmony_ci conn_type = HTTP_CONNECTION_CLOSE; 1695d4afb5ceSopenharmony_ci 1696d4afb5ceSopenharmony_ci /* Override default if http "Connection:" header: */ 1697d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION) && 1698d4afb5ceSopenharmony_ci lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1, 1699d4afb5ceSopenharmony_ci WSI_TOKEN_CONNECTION) > 0) { 1700d4afb5ceSopenharmony_ci http_conn_str[sizeof(http_conn_str) - 1] = '\0'; 1701d4afb5ceSopenharmony_ci if (!strcasecmp(http_conn_str, "keep-alive")) 1702d4afb5ceSopenharmony_ci conn_type = HTTP_CONNECTION_KEEP_ALIVE; 1703d4afb5ceSopenharmony_ci else 1704d4afb5ceSopenharmony_ci if (!strcasecmp(http_conn_str, "close")) 1705d4afb5ceSopenharmony_ci conn_type = HTTP_CONNECTION_CLOSE; 1706d4afb5ceSopenharmony_ci } 1707d4afb5ceSopenharmony_ci wsi->http.conn_type = conn_type; 1708d4afb5ceSopenharmony_ci } 1709d4afb5ceSopenharmony_ci 1710d4afb5ceSopenharmony_ci n = (unsigned int)wsi->a.protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION, 1711d4afb5ceSopenharmony_ci wsi->user_space, uri_ptr, (unsigned int)uri_len); 1712d4afb5ceSopenharmony_ci if (n) { 1713d4afb5ceSopenharmony_ci lwsl_info("LWS_CALLBACK_HTTP closing\n"); 1714d4afb5ceSopenharmony_ci 1715d4afb5ceSopenharmony_ci return 1; 1716d4afb5ceSopenharmony_ci } 1717d4afb5ceSopenharmony_ci /* 1718d4afb5ceSopenharmony_ci * if there is content supposed to be coming, 1719d4afb5ceSopenharmony_ci * put a timeout on it having arrived 1720d4afb5ceSopenharmony_ci */ 1721d4afb5ceSopenharmony_ci if (!wsi->mux_stream_immortal) 1722d4afb5ceSopenharmony_ci lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 1723d4afb5ceSopenharmony_ci (int)wsi->a.context->timeout_secs); 1724d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 1725d4afb5ceSopenharmony_ci if (wsi->tls.redirect_to_https) { 1726d4afb5ceSopenharmony_ci /* 1727d4afb5ceSopenharmony_ci * We accepted http:// only so we could redirect to 1728d4afb5ceSopenharmony_ci * https://, so issue the redirect. Create the redirection 1729d4afb5ceSopenharmony_ci * URI from the host: header, and regenerate the path part from 1730d4afb5ceSopenharmony_ci * the parsed pieces 1731d4afb5ceSopenharmony_ci */ 1732d4afb5ceSopenharmony_ci unsigned char *start = pt->serv_buf + LWS_PRE, *p = start, 1733d4afb5ceSopenharmony_ci *end = p + wsi->a.context->pt_serv_buf_size - 1734d4afb5ceSopenharmony_ci LWS_PRE; 1735d4afb5ceSopenharmony_ci 1736d4afb5ceSopenharmony_ci n = (unsigned int)lws_hdr_total_length(wsi, WSI_TOKEN_HOST); 1737d4afb5ceSopenharmony_ci if (!n || n > 128) 1738d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1739d4afb5ceSopenharmony_ci 1740d4afb5ceSopenharmony_ci if (!lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)) 1741d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1742d4afb5ceSopenharmony_ci 1743d4afb5ceSopenharmony_ci p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "https://"); 1744d4afb5ceSopenharmony_ci memcpy(p, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST), n); 1745d4afb5ceSopenharmony_ci p += n; 1746d4afb5ceSopenharmony_ci *p++ = '/'; 1747d4afb5ceSopenharmony_ci if (uri_len >= lws_ptr_diff(end, p)) 1748d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1749d4afb5ceSopenharmony_ci 1750d4afb5ceSopenharmony_ci if (uri_ptr[0]) 1751d4afb5ceSopenharmony_ci p--; 1752d4afb5ceSopenharmony_ci memcpy(p, uri_ptr, (unsigned int)uri_len); 1753d4afb5ceSopenharmony_ci p += uri_len; 1754d4afb5ceSopenharmony_ci 1755d4afb5ceSopenharmony_ci n = 0; 1756d4afb5ceSopenharmony_ci while (lws_hdr_copy_fragment(wsi, (char *)p + 1, 1757d4afb5ceSopenharmony_ci lws_ptr_diff(end, p) - 2, 1758d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_URI_ARGS, (int)n) > 0) { 1759d4afb5ceSopenharmony_ci *p = n ? '&' : '?'; 1760d4afb5ceSopenharmony_ci p += strlen((char *)p); 1761d4afb5ceSopenharmony_ci if (p >= end - 2) 1762d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1763d4afb5ceSopenharmony_ci n++; 1764d4afb5ceSopenharmony_ci } 1765d4afb5ceSopenharmony_ci 1766d4afb5ceSopenharmony_ci n = (unsigned int)lws_ptr_diff(p, start); 1767d4afb5ceSopenharmony_ci 1768d4afb5ceSopenharmony_ci p += LWS_PRE; 1769d4afb5ceSopenharmony_ci n = (unsigned int)lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY, 1770d4afb5ceSopenharmony_ci start, (int)n, &p, end); 1771d4afb5ceSopenharmony_ci if ((int)n < 0) 1772d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1773d4afb5ceSopenharmony_ci 1774d4afb5ceSopenharmony_ci return lws_http_transaction_completed(wsi); 1775d4afb5ceSopenharmony_ci } 1776d4afb5ceSopenharmony_ci#endif 1777d4afb5ceSopenharmony_ci 1778d4afb5ceSopenharmony_ci#ifdef LWS_WITH_ACCESS_LOG 1779d4afb5ceSopenharmony_ci lws_prepare_access_log_info(wsi, uri_ptr, uri_len, meth); 1780d4afb5ceSopenharmony_ci#endif 1781d4afb5ceSopenharmony_ci 1782d4afb5ceSopenharmony_ci /* can we serve it from the mount list? */ 1783d4afb5ceSopenharmony_ci 1784d4afb5ceSopenharmony_ci hit = lws_find_mount(wsi, uri_ptr, uri_len); 1785d4afb5ceSopenharmony_ci if (!hit) { 1786d4afb5ceSopenharmony_ci /* deferred cleanup and reset to protocols[0] */ 1787d4afb5ceSopenharmony_ci 1788d4afb5ceSopenharmony_ci lwsl_info("no hit\n"); 1789d4afb5ceSopenharmony_ci 1790d4afb5ceSopenharmony_ci if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[0], 1791d4afb5ceSopenharmony_ci "no mount hit")) 1792d4afb5ceSopenharmony_ci return 1; 1793d4afb5ceSopenharmony_ci 1794d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_DOING_TRANSACTION); 1795d4afb5ceSopenharmony_ci 1796d4afb5ceSopenharmony_ci m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP, 1797d4afb5ceSopenharmony_ci wsi->user_space, uri_ptr, (unsigned int)uri_len); 1798d4afb5ceSopenharmony_ci 1799d4afb5ceSopenharmony_ci goto after; 1800d4afb5ceSopenharmony_ci } 1801d4afb5ceSopenharmony_ci 1802d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 1803d4afb5ceSopenharmony_ci s = uri_ptr + hit->mountpoint_len; 1804d4afb5ceSopenharmony_ci#endif 1805d4afb5ceSopenharmony_ci n = (unsigned int)lws_http_redirect_hit(pt, wsi, hit, uri_ptr, uri_len, &ha); 1806d4afb5ceSopenharmony_ci if (ha) 1807d4afb5ceSopenharmony_ci return (int)n; 1808d4afb5ceSopenharmony_ci 1809d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_BASIC_AUTH) 1810d4afb5ceSopenharmony_ci 1811d4afb5ceSopenharmony_ci /* basic auth? */ 1812d4afb5ceSopenharmony_ci 1813d4afb5ceSopenharmony_ci switch (lws_check_basic_auth(wsi, hit->basic_auth_login_file, 1814d4afb5ceSopenharmony_ci hit->auth_mask & AUTH_MODE_MASK)) { 1815d4afb5ceSopenharmony_ci case LCBA_CONTINUE: 1816d4afb5ceSopenharmony_ci break; 1817d4afb5ceSopenharmony_ci case LCBA_FAILED_AUTH: 1818d4afb5ceSopenharmony_ci return lws_unauthorised_basic_auth(wsi); 1819d4afb5ceSopenharmony_ci case LCBA_END_TRANSACTION: 1820d4afb5ceSopenharmony_ci lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL); 1821d4afb5ceSopenharmony_ci return lws_http_transaction_completed(wsi); 1822d4afb5ceSopenharmony_ci } 1823d4afb5ceSopenharmony_ci#endif 1824d4afb5ceSopenharmony_ci 1825d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 1826d4afb5ceSopenharmony_ci /* 1827d4afb5ceSopenharmony_ci * The mount is a reverse proxy? 1828d4afb5ceSopenharmony_ci */ 1829d4afb5ceSopenharmony_ci 1830d4afb5ceSopenharmony_ci // if (hit) 1831d4afb5ceSopenharmony_ci // lwsl_notice("%s: origin_protocol: %d\n", __func__, hit->origin_protocol); 1832d4afb5ceSopenharmony_ci //else 1833d4afb5ceSopenharmony_ci // lwsl_notice("%s: no hit\n", __func__); 1834d4afb5ceSopenharmony_ci 1835d4afb5ceSopenharmony_ci if (hit->origin_protocol == LWSMPRO_HTTPS || 1836d4afb5ceSopenharmony_ci hit->origin_protocol == LWSMPRO_HTTP) { 1837d4afb5ceSopenharmony_ci n = (unsigned int)lws_http_proxy_start(wsi, hit, uri_ptr, 0); 1838d4afb5ceSopenharmony_ci // lwsl_notice("proxy start says %d\n", n); 1839d4afb5ceSopenharmony_ci if (n) 1840d4afb5ceSopenharmony_ci return (int)n; 1841d4afb5ceSopenharmony_ci 1842d4afb5ceSopenharmony_ci goto deal_body; 1843d4afb5ceSopenharmony_ci } 1844d4afb5ceSopenharmony_ci#endif 1845d4afb5ceSopenharmony_ci 1846d4afb5ceSopenharmony_ci /* 1847d4afb5ceSopenharmony_ci * A particular protocol callback is mounted here? 1848d4afb5ceSopenharmony_ci * 1849d4afb5ceSopenharmony_ci * For the duration of this http transaction, bind us to the 1850d4afb5ceSopenharmony_ci * associated protocol 1851d4afb5ceSopenharmony_ci */ 1852d4afb5ceSopenharmony_ci if (hit->origin_protocol == LWSMPRO_CALLBACK || hit->protocol) { 1853d4afb5ceSopenharmony_ci const struct lws_protocols *pp; 1854d4afb5ceSopenharmony_ci const char *name = hit->origin; 1855d4afb5ceSopenharmony_ci if (hit->protocol) 1856d4afb5ceSopenharmony_ci name = hit->protocol; 1857d4afb5ceSopenharmony_ci 1858d4afb5ceSopenharmony_ci pp = lws_vhost_name_to_protocol(wsi->a.vhost, name); 1859d4afb5ceSopenharmony_ci if (!pp) { 1860d4afb5ceSopenharmony_ci lwsl_err("Unable to find plugin '%s'\n", 1861d4afb5ceSopenharmony_ci name); 1862d4afb5ceSopenharmony_ci return 1; 1863d4afb5ceSopenharmony_ci } 1864d4afb5ceSopenharmony_ci 1865d4afb5ceSopenharmony_ci if (lws_bind_protocol(wsi, pp, "http action CALLBACK bind")) 1866d4afb5ceSopenharmony_ci return 1; 1867d4afb5ceSopenharmony_ci 1868d4afb5ceSopenharmony_ci lwsl_debug("%s: %s, checking access rights for mask 0x%x\n", 1869d4afb5ceSopenharmony_ci __func__, hit->origin, hit->auth_mask); 1870d4afb5ceSopenharmony_ci 1871d4afb5ceSopenharmony_ci args.p = uri_ptr; 1872d4afb5ceSopenharmony_ci args.len = uri_len; 1873d4afb5ceSopenharmony_ci args.max_len = hit->auth_mask & ~AUTH_MODE_MASK; 1874d4afb5ceSopenharmony_ci args.final = 0; /* used to signal callback dealt with it */ 1875d4afb5ceSopenharmony_ci args.chunked = 0; 1876d4afb5ceSopenharmony_ci 1877d4afb5ceSopenharmony_ci n = (unsigned int)wsi->a.protocol->callback(wsi, 1878d4afb5ceSopenharmony_ci LWS_CALLBACK_CHECK_ACCESS_RIGHTS, 1879d4afb5ceSopenharmony_ci wsi->user_space, &args, 0); 1880d4afb5ceSopenharmony_ci if (n) { 1881d4afb5ceSopenharmony_ci lws_return_http_status(wsi, HTTP_STATUS_UNAUTHORIZED, 1882d4afb5ceSopenharmony_ci NULL); 1883d4afb5ceSopenharmony_ci goto bail_nuke_ah; 1884d4afb5ceSopenharmony_ci } 1885d4afb5ceSopenharmony_ci if (args.final) /* callback completely handled it well */ 1886d4afb5ceSopenharmony_ci return 0; 1887d4afb5ceSopenharmony_ci 1888d4afb5ceSopenharmony_ci if (hit->cgienv && wsi->a.protocol->callback(wsi, 1889d4afb5ceSopenharmony_ci LWS_CALLBACK_HTTP_PMO, 1890d4afb5ceSopenharmony_ci wsi->user_space, (void *)hit->cgienv, 0)) 1891d4afb5ceSopenharmony_ci return 1; 1892d4afb5ceSopenharmony_ci 1893d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { 1894d4afb5ceSopenharmony_ci m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP, 1895d4afb5ceSopenharmony_ci wsi->user_space, 1896d4afb5ceSopenharmony_ci uri_ptr + hit->mountpoint_len, 1897d4afb5ceSopenharmony_ci (unsigned int)uri_len - hit->mountpoint_len); 1898d4afb5ceSopenharmony_ci goto after; 1899d4afb5ceSopenharmony_ci } 1900d4afb5ceSopenharmony_ci } 1901d4afb5ceSopenharmony_ci 1902d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI 1903d4afb5ceSopenharmony_ci /* did we hit something with a cgi:// origin? */ 1904d4afb5ceSopenharmony_ci if (hit->origin_protocol == LWSMPRO_CGI) { 1905d4afb5ceSopenharmony_ci const char *cmd[] = { 1906d4afb5ceSopenharmony_ci NULL, /* replace with cgi path */ 1907d4afb5ceSopenharmony_ci NULL 1908d4afb5ceSopenharmony_ci }; 1909d4afb5ceSopenharmony_ci 1910d4afb5ceSopenharmony_ci lwsl_debug("%s: cgi\n", __func__); 1911d4afb5ceSopenharmony_ci cmd[0] = hit->origin; 1912d4afb5ceSopenharmony_ci 1913d4afb5ceSopenharmony_ci n = 5; 1914d4afb5ceSopenharmony_ci if (hit->cgi_timeout) 1915d4afb5ceSopenharmony_ci n = (unsigned int)hit->cgi_timeout; 1916d4afb5ceSopenharmony_ci 1917d4afb5ceSopenharmony_ci n = (unsigned int)lws_cgi(wsi, cmd, hit->mountpoint_len, (int)n, 1918d4afb5ceSopenharmony_ci hit->cgienv); 1919d4afb5ceSopenharmony_ci if (n) { 1920d4afb5ceSopenharmony_ci lwsl_err("%s: cgi failed\n", __func__); 1921d4afb5ceSopenharmony_ci return -1; 1922d4afb5ceSopenharmony_ci } 1923d4afb5ceSopenharmony_ci 1924d4afb5ceSopenharmony_ci goto deal_body; 1925d4afb5ceSopenharmony_ci } 1926d4afb5ceSopenharmony_ci#endif 1927d4afb5ceSopenharmony_ci 1928d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 1929d4afb5ceSopenharmony_ci n = (unsigned int)(uri_len - lws_ptr_diff(s, uri_ptr)); 1930d4afb5ceSopenharmony_ci if (s[0] == '\0' || (n == 1 && s[n - 1] == '/')) 1931d4afb5ceSopenharmony_ci s = (char *)hit->def; 1932d4afb5ceSopenharmony_ci if (!s) 1933d4afb5ceSopenharmony_ci s = "index.html"; 1934d4afb5ceSopenharmony_ci#endif 1935d4afb5ceSopenharmony_ci 1936d4afb5ceSopenharmony_ci wsi->cache_secs = (unsigned int)hit->cache_max_age; 1937d4afb5ceSopenharmony_ci wsi->cache_reuse = hit->cache_reusable; 1938d4afb5ceSopenharmony_ci wsi->cache_revalidate = hit->cache_revalidate; 1939d4afb5ceSopenharmony_ci wsi->cache_intermediaries = hit->cache_intermediaries; 1940d4afb5ceSopenharmony_ci 1941d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 1942d4afb5ceSopenharmony_ci m = 1; 1943d4afb5ceSopenharmony_ci if (hit->origin_protocol == LWSMPRO_FILE) 1944d4afb5ceSopenharmony_ci m = lws_http_serve(wsi, s, hit->origin, hit); 1945d4afb5ceSopenharmony_ci 1946d4afb5ceSopenharmony_ci if (m > 0) 1947d4afb5ceSopenharmony_ci#endif 1948d4afb5ceSopenharmony_ci { 1949d4afb5ceSopenharmony_ci /* 1950d4afb5ceSopenharmony_ci * lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL); 1951d4afb5ceSopenharmony_ci */ 1952d4afb5ceSopenharmony_ci if (hit->protocol) { 1953d4afb5ceSopenharmony_ci const struct lws_protocols *pp = 1954d4afb5ceSopenharmony_ci lws_vhost_name_to_protocol( 1955d4afb5ceSopenharmony_ci wsi->a.vhost, hit->protocol); 1956d4afb5ceSopenharmony_ci 1957d4afb5ceSopenharmony_ci /* coverity */ 1958d4afb5ceSopenharmony_ci if (!pp) 1959d4afb5ceSopenharmony_ci return 1; 1960d4afb5ceSopenharmony_ci 1961d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_DOING_TRANSACTION); 1962d4afb5ceSopenharmony_ci 1963d4afb5ceSopenharmony_ci if (lws_bind_protocol(wsi, pp, "http_action HTTP")) 1964d4afb5ceSopenharmony_ci return 1; 1965d4afb5ceSopenharmony_ci 1966d4afb5ceSopenharmony_ci m = pp->callback(wsi, LWS_CALLBACK_HTTP, 1967d4afb5ceSopenharmony_ci wsi->user_space, 1968d4afb5ceSopenharmony_ci uri_ptr + hit->mountpoint_len, 1969d4afb5ceSopenharmony_ci (size_t)(uri_len - hit->mountpoint_len)); 1970d4afb5ceSopenharmony_ci } else 1971d4afb5ceSopenharmony_ci m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP, 1972d4afb5ceSopenharmony_ci wsi->user_space, uri_ptr, (size_t)uri_len); 1973d4afb5ceSopenharmony_ci } 1974d4afb5ceSopenharmony_ci 1975d4afb5ceSopenharmony_ciafter: 1976d4afb5ceSopenharmony_ci if (m) { 1977d4afb5ceSopenharmony_ci lwsl_info("LWS_CALLBACK_HTTP closing\n"); 1978d4afb5ceSopenharmony_ci 1979d4afb5ceSopenharmony_ci return 1; 1980d4afb5ceSopenharmony_ci } 1981d4afb5ceSopenharmony_ci 1982d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY) 1983d4afb5ceSopenharmony_cideal_body: 1984d4afb5ceSopenharmony_ci#endif 1985d4afb5ceSopenharmony_ci /* 1986d4afb5ceSopenharmony_ci * If we're not issuing a file, check for content_length or 1987d4afb5ceSopenharmony_ci * HTTP keep-alive. No keep-alive header allocation for 1988d4afb5ceSopenharmony_ci * ISSUING_FILE, as this uses HTTP/1.0. 1989d4afb5ceSopenharmony_ci * 1990d4afb5ceSopenharmony_ci * In any case, return 0 and let lws_read decide how to 1991d4afb5ceSopenharmony_ci * proceed based on state 1992d4afb5ceSopenharmony_ci */ 1993d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_ISSUING_FILE) 1994d4afb5ceSopenharmony_ci return 0; 1995d4afb5ceSopenharmony_ci 1996d4afb5ceSopenharmony_ci /* Prepare to read body if we have a content length: */ 1997d4afb5ceSopenharmony_ci lwsl_debug("wsi->http.rx_content_length %lld %d %d\n", 1998d4afb5ceSopenharmony_ci (long long)wsi->http.rx_content_length, 1999d4afb5ceSopenharmony_ci wsi->upgraded_to_http2, wsi->mux_substream); 2000d4afb5ceSopenharmony_ci 2001d4afb5ceSopenharmony_ci if (wsi->http.content_length_explicitly_zero && 2002d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { 2003d4afb5ceSopenharmony_ci 2004d4afb5ceSopenharmony_ci /* 2005d4afb5ceSopenharmony_ci * POST with an explicit content-length of zero 2006d4afb5ceSopenharmony_ci * 2007d4afb5ceSopenharmony_ci * If we don't give the user code the empty HTTP_BODY callback, 2008d4afb5ceSopenharmony_ci * he may become confused to hear the HTTP_BODY_COMPLETION (due 2009d4afb5ceSopenharmony_ci * to, eg, instantiation of lws_spa never happened). 2010d4afb5ceSopenharmony_ci * 2011d4afb5ceSopenharmony_ci * HTTP_BODY_COMPLETION is responsible for sending the result 2012d4afb5ceSopenharmony_ci * status code and result body if any, and to do the transaction 2013d4afb5ceSopenharmony_ci * complete processing. 2014d4afb5ceSopenharmony_ci */ 2015d4afb5ceSopenharmony_ci if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY, 2016d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0)) 2017d4afb5ceSopenharmony_ci return 1; 2018d4afb5ceSopenharmony_ci if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY_COMPLETION, 2019d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0)) 2020d4afb5ceSopenharmony_ci return 1; 2021d4afb5ceSopenharmony_ci 2022d4afb5ceSopenharmony_ci return 0; 2023d4afb5ceSopenharmony_ci } 2024d4afb5ceSopenharmony_ci 2025d4afb5ceSopenharmony_ci if (wsi->http.rx_content_length <= 0) 2026d4afb5ceSopenharmony_ci return 0; 2027d4afb5ceSopenharmony_ci 2028d4afb5ceSopenharmony_ci if (lwsi_state(wsi) != LRS_DISCARD_BODY) { 2029d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_BODY); 2030d4afb5ceSopenharmony_ci lwsl_info("%s: %s: LRS_BODY state set (0x%x)\n", __func__, 2031d4afb5ceSopenharmony_ci lws_wsi_tag(wsi), (int)wsi->wsistate); 2032d4afb5ceSopenharmony_ci } 2033d4afb5ceSopenharmony_ci wsi->http.rx_content_remain = wsi->http.rx_content_length; 2034d4afb5ceSopenharmony_ci 2035d4afb5ceSopenharmony_ci /* 2036d4afb5ceSopenharmony_ci * At this point we have transitioned from deferred 2037d4afb5ceSopenharmony_ci * action to expecting BODY on the stream wsi, if it's 2038d4afb5ceSopenharmony_ci * in a bundle like h2. So if the stream wsi has its 2039d4afb5ceSopenharmony_ci * own buflist, we need to deal with that first. 2040d4afb5ceSopenharmony_ci */ 2041d4afb5ceSopenharmony_ci 2042d4afb5ceSopenharmony_ci while (1) { 2043d4afb5ceSopenharmony_ci struct lws_tokens ebuf; 2044d4afb5ceSopenharmony_ci int m; 2045d4afb5ceSopenharmony_ci 2046d4afb5ceSopenharmony_ci ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist, 2047d4afb5ceSopenharmony_ci &ebuf.token); 2048d4afb5ceSopenharmony_ci if (!ebuf.len) 2049d4afb5ceSopenharmony_ci break; 2050d4afb5ceSopenharmony_ci 2051d4afb5ceSopenharmony_ci lwsl_debug("%s: consuming %d\n", __func__, (int)ebuf.len); 2052d4afb5ceSopenharmony_ci m = lws_read_h1(wsi, ebuf.token, (lws_filepos_t)ebuf.len); 2053d4afb5ceSopenharmony_ci if (m < 0) 2054d4afb5ceSopenharmony_ci return -1; 2055d4afb5ceSopenharmony_ci 2056d4afb5ceSopenharmony_ci if (lws_buflist_aware_finished_consuming(wsi, &ebuf, m, 1, 2057d4afb5ceSopenharmony_ci __func__)) 2058d4afb5ceSopenharmony_ci return -1; 2059d4afb5ceSopenharmony_ci } 2060d4afb5ceSopenharmony_ci 2061d4afb5ceSopenharmony_ci return 0; 2062d4afb5ceSopenharmony_ci 2063d4afb5ceSopenharmony_cibail_nuke_ah: 2064d4afb5ceSopenharmony_ci lws_header_table_detach(wsi, 1); 2065d4afb5ceSopenharmony_ci 2066d4afb5ceSopenharmony_ci return 1; 2067d4afb5ceSopenharmony_ci} 2068d4afb5ceSopenharmony_ci 2069d4afb5ceSopenharmony_ciint 2070d4afb5ceSopenharmony_cilws_confirm_host_header(struct lws *wsi) 2071d4afb5ceSopenharmony_ci{ 2072d4afb5ceSopenharmony_ci struct lws_tokenize ts; 2073d4afb5ceSopenharmony_ci lws_tokenize_elem e; 2074d4afb5ceSopenharmony_ci int port = 80, n; 2075d4afb5ceSopenharmony_ci char buf[128]; 2076d4afb5ceSopenharmony_ci 2077d4afb5ceSopenharmony_ci /* 2078d4afb5ceSopenharmony_ci * this vhost wants us to validate what the 2079d4afb5ceSopenharmony_ci * client sent against our vhost name 2080d4afb5ceSopenharmony_ci */ 2081d4afb5ceSopenharmony_ci 2082d4afb5ceSopenharmony_ci if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { 2083d4afb5ceSopenharmony_ci lwsl_info("%s: missing host on upgrade\n", __func__); 2084d4afb5ceSopenharmony_ci 2085d4afb5ceSopenharmony_ci return 1; 2086d4afb5ceSopenharmony_ci } 2087d4afb5ceSopenharmony_ci 2088d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 2089d4afb5ceSopenharmony_ci if (wsi->tls.ssl) 2090d4afb5ceSopenharmony_ci port = 443; 2091d4afb5ceSopenharmony_ci#endif 2092d4afb5ceSopenharmony_ci 2093d4afb5ceSopenharmony_ci n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_HOST); 2094d4afb5ceSopenharmony_ci if (n <= 0) { 2095d4afb5ceSopenharmony_ci lwsl_info("%s: missing or oversize host header\n", __func__); 2096d4afb5ceSopenharmony_ci return 1; 2097d4afb5ceSopenharmony_ci } 2098d4afb5ceSopenharmony_ci ts.len = (size_t)n; 2099d4afb5ceSopenharmony_ci lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_DOT_NONTERM /* server.com */| 2100d4afb5ceSopenharmony_ci LWS_TOKENIZE_F_NO_FLOATS /* 1.server.com */| 2101d4afb5ceSopenharmony_ci LWS_TOKENIZE_F_MINUS_NONTERM /* a-b.com */); 2102d4afb5ceSopenharmony_ci 2103d4afb5ceSopenharmony_ci if (lws_tokenize(&ts) != LWS_TOKZE_TOKEN) 2104d4afb5ceSopenharmony_ci goto bad_format; 2105d4afb5ceSopenharmony_ci 2106d4afb5ceSopenharmony_ci if (strncmp(ts.token, wsi->a.vhost->name, ts.token_len)) { 2107d4afb5ceSopenharmony_ci buf[(size_t)(ts.token - buf) + ts.token_len] = '\0'; 2108d4afb5ceSopenharmony_ci lwsl_info("%s: '%s' in host hdr but vhost name %s\n", 2109d4afb5ceSopenharmony_ci __func__, ts.token, wsi->a.vhost->name); 2110d4afb5ceSopenharmony_ci return 1; 2111d4afb5ceSopenharmony_ci } 2112d4afb5ceSopenharmony_ci 2113d4afb5ceSopenharmony_ci e = lws_tokenize(&ts); 2114d4afb5ceSopenharmony_ci if (e == LWS_TOKZE_DELIMITER && ts.token[0] == ':') { 2115d4afb5ceSopenharmony_ci if (lws_tokenize(&ts) != LWS_TOKZE_INTEGER) 2116d4afb5ceSopenharmony_ci goto bad_format; 2117d4afb5ceSopenharmony_ci else 2118d4afb5ceSopenharmony_ci port = atoi(ts.token); 2119d4afb5ceSopenharmony_ci } else 2120d4afb5ceSopenharmony_ci if (e != LWS_TOKZE_ENDED) 2121d4afb5ceSopenharmony_ci goto bad_format; 2122d4afb5ceSopenharmony_ci 2123d4afb5ceSopenharmony_ci if (wsi->a.vhost->listen_port != port) { 2124d4afb5ceSopenharmony_ci lwsl_info("%s: host port %d mismatches vhost port %d\n", 2125d4afb5ceSopenharmony_ci __func__, port, wsi->a.vhost->listen_port); 2126d4afb5ceSopenharmony_ci return 1; 2127d4afb5ceSopenharmony_ci } 2128d4afb5ceSopenharmony_ci 2129d4afb5ceSopenharmony_ci lwsl_debug("%s: host header OK\n", __func__); 2130d4afb5ceSopenharmony_ci 2131d4afb5ceSopenharmony_ci return 0; 2132d4afb5ceSopenharmony_ci 2133d4afb5ceSopenharmony_cibad_format: 2134d4afb5ceSopenharmony_ci lwsl_info("%s: bad host header format\n", __func__); 2135d4afb5ceSopenharmony_ci 2136d4afb5ceSopenharmony_ci return 1; 2137d4afb5ceSopenharmony_ci} 2138d4afb5ceSopenharmony_ci 2139d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 2140d4afb5ceSopenharmony_ciint 2141d4afb5ceSopenharmony_cilws_http_to_fallback(struct lws *wsi, unsigned char *obuf, size_t olen) 2142d4afb5ceSopenharmony_ci{ 2143d4afb5ceSopenharmony_ci const struct lws_role_ops *role = &role_ops_raw_skt; 2144d4afb5ceSopenharmony_ci const struct lws_protocols *p1, *protocol = 2145d4afb5ceSopenharmony_ci &wsi->a.vhost->protocols[wsi->a.vhost->raw_protocol_index]; 2146d4afb5ceSopenharmony_ci char ipbuf[64]; 2147d4afb5ceSopenharmony_ci int n; 2148d4afb5ceSopenharmony_ci 2149d4afb5ceSopenharmony_ci if (wsi->a.vhost->listen_accept_role && 2150d4afb5ceSopenharmony_ci lws_role_by_name(wsi->a.vhost->listen_accept_role)) 2151d4afb5ceSopenharmony_ci role = lws_role_by_name(wsi->a.vhost->listen_accept_role); 2152d4afb5ceSopenharmony_ci 2153d4afb5ceSopenharmony_ci if (wsi->a.vhost->listen_accept_protocol) { 2154d4afb5ceSopenharmony_ci p1 = lws_vhost_name_to_protocol(wsi->a.vhost, 2155d4afb5ceSopenharmony_ci wsi->a.vhost->listen_accept_protocol); 2156d4afb5ceSopenharmony_ci if (p1) 2157d4afb5ceSopenharmony_ci protocol = p1; 2158d4afb5ceSopenharmony_ci } 2159d4afb5ceSopenharmony_ci 2160d4afb5ceSopenharmony_ci lws_bind_protocol(wsi, protocol, __func__); 2161d4afb5ceSopenharmony_ci 2162d4afb5ceSopenharmony_ci lws_role_transition(wsi, LWSIFR_SERVER, LRS_ESTABLISHED, role); 2163d4afb5ceSopenharmony_ci 2164d4afb5ceSopenharmony_ci lws_header_table_detach(wsi, 0); 2165d4afb5ceSopenharmony_ci lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); 2166d4afb5ceSopenharmony_ci 2167d4afb5ceSopenharmony_ci n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED; 2168d4afb5ceSopenharmony_ci if (wsi->role_ops->adoption_cb[1]) 2169d4afb5ceSopenharmony_ci n = wsi->role_ops->adoption_cb[1]; 2170d4afb5ceSopenharmony_ci 2171d4afb5ceSopenharmony_ci ipbuf[0] = '\0'; 2172d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) 2173d4afb5ceSopenharmony_ci lws_get_peer_simple(wsi, ipbuf, sizeof(ipbuf)); 2174d4afb5ceSopenharmony_ci#endif 2175d4afb5ceSopenharmony_ci 2176d4afb5ceSopenharmony_ci lwsl_notice("%s: vh %s, peer: %s, role %s, " 2177d4afb5ceSopenharmony_ci "protocol %s, cb %d, ah %p\n", __func__, wsi->a.vhost->name, 2178d4afb5ceSopenharmony_ci ipbuf, role ? role->name : "null", protocol->name, n, 2179d4afb5ceSopenharmony_ci wsi->http.ah); 2180d4afb5ceSopenharmony_ci 2181d4afb5ceSopenharmony_ci if ((wsi->a.protocol->callback)(wsi, (enum lws_callback_reasons)n, wsi->user_space, NULL, 0)) 2182d4afb5ceSopenharmony_ci return 1; 2183d4afb5ceSopenharmony_ci 2184d4afb5ceSopenharmony_ci n = LWS_CALLBACK_RAW_RX; 2185d4afb5ceSopenharmony_ci if (wsi->role_ops->rx_cb[lwsi_role_server(wsi)]) 2186d4afb5ceSopenharmony_ci n = wsi->role_ops->rx_cb[lwsi_role_server(wsi)]; 2187d4afb5ceSopenharmony_ci if (wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)n, wsi->user_space, obuf, olen)) 2188d4afb5ceSopenharmony_ci return 1; 2189d4afb5ceSopenharmony_ci 2190d4afb5ceSopenharmony_ci return 0; 2191d4afb5ceSopenharmony_ci} 2192d4afb5ceSopenharmony_ci 2193d4afb5ceSopenharmony_ciint 2194d4afb5ceSopenharmony_cilws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len) 2195d4afb5ceSopenharmony_ci{ 2196d4afb5ceSopenharmony_ci struct lws_context *context = lws_get_context(wsi); 2197d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 2198d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 2199d4afb5ceSopenharmony_ci struct allocated_headers *ah; 2200d4afb5ceSopenharmony_ci#endif 2201d4afb5ceSopenharmony_ci unsigned char *obuf = *buf; 2202d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 2203d4afb5ceSopenharmony_ci char tbuf[128], *p; 2204d4afb5ceSopenharmony_ci#endif 2205d4afb5ceSopenharmony_ci size_t olen = len; 2206d4afb5ceSopenharmony_ci int n = 0, m, i; 2207d4afb5ceSopenharmony_ci 2208d4afb5ceSopenharmony_ci if (len >= 10000000) { 2209d4afb5ceSopenharmony_ci lwsl_err("%s: assert: len %ld\n", __func__, (long)len); 2210d4afb5ceSopenharmony_ci assert(0); 2211d4afb5ceSopenharmony_ci } 2212d4afb5ceSopenharmony_ci 2213d4afb5ceSopenharmony_ci if (!wsi->http.ah) { 2214d4afb5ceSopenharmony_ci lwsl_err("%s: assert: NULL ah\n", __func__); 2215d4afb5ceSopenharmony_ci assert(0); 2216d4afb5ceSopenharmony_ci } 2217d4afb5ceSopenharmony_ci 2218d4afb5ceSopenharmony_ci while (len) { 2219d4afb5ceSopenharmony_ci if (!lwsi_role_server(wsi) || !lwsi_role_http(wsi)) { 2220d4afb5ceSopenharmony_ci lwsl_err("%s: bad wsi role 0x%x\n", __func__, 2221d4afb5ceSopenharmony_ci (int)lwsi_role(wsi)); 2222d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2223d4afb5ceSopenharmony_ci } 2224d4afb5ceSopenharmony_ci 2225d4afb5ceSopenharmony_ci i = (int)len; 2226d4afb5ceSopenharmony_ci m = lws_parse(wsi, *buf, &i); 2227d4afb5ceSopenharmony_ci lwsl_info("%s: parsed count %d\n", __func__, (int)len - i); 2228d4afb5ceSopenharmony_ci (*buf) += (int)len - i; 2229d4afb5ceSopenharmony_ci len = (unsigned int)i; 2230d4afb5ceSopenharmony_ci 2231d4afb5ceSopenharmony_ci if (m == LPR_DO_FALLBACK) { 2232d4afb5ceSopenharmony_ci 2233d4afb5ceSopenharmony_ci /* 2234d4afb5ceSopenharmony_ci * http parser went off the rails and 2235d4afb5ceSopenharmony_ci * LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ 2236d4afb5ceSopenharmony_ci * ACCEPT_CONFIG is set on this vhost. 2237d4afb5ceSopenharmony_ci * 2238d4afb5ceSopenharmony_ci * We are transitioning from http with an AH, to 2239d4afb5ceSopenharmony_ci * a backup role (raw-skt, by default). Drop 2240d4afb5ceSopenharmony_ci * the ah, bind to the role with mode as 2241d4afb5ceSopenharmony_ci * ESTABLISHED. 2242d4afb5ceSopenharmony_ci */ 2243d4afb5ceSopenharmony_ciraw_transition: 2244d4afb5ceSopenharmony_ci 2245d4afb5ceSopenharmony_ci if (lws_http_to_fallback(wsi, obuf, olen)) { 2246d4afb5ceSopenharmony_ci lwsl_info("%s: fallback -> close\n", __func__); 2247d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2248d4afb5ceSopenharmony_ci } 2249d4afb5ceSopenharmony_ci 2250d4afb5ceSopenharmony_ci (*buf) = obuf + olen; 2251d4afb5ceSopenharmony_ci 2252d4afb5ceSopenharmony_ci return 0; 2253d4afb5ceSopenharmony_ci } 2254d4afb5ceSopenharmony_ci if (m) { 2255d4afb5ceSopenharmony_ci lwsl_info("lws_parse failed\n"); 2256d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2257d4afb5ceSopenharmony_ci } 2258d4afb5ceSopenharmony_ci 2259d4afb5ceSopenharmony_ci /* coverity... */ 2260d4afb5ceSopenharmony_ci if (!wsi->http.ah) 2261d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2262d4afb5ceSopenharmony_ci 2263d4afb5ceSopenharmony_ci if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE) 2264d4afb5ceSopenharmony_ci continue; 2265d4afb5ceSopenharmony_ci 2266d4afb5ceSopenharmony_ci lwsl_parser("%s: lws_parse sees parsing complete\n", __func__); 2267d4afb5ceSopenharmony_ci 2268d4afb5ceSopenharmony_ci /* select vhost */ 2269d4afb5ceSopenharmony_ci 2270d4afb5ceSopenharmony_ci if (wsi->a.vhost->listen_port && 2271d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { 2272d4afb5ceSopenharmony_ci struct lws_vhost *vhost = lws_select_vhost( 2273d4afb5ceSopenharmony_ci context, wsi->a.vhost->listen_port, 2274d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)); 2275d4afb5ceSopenharmony_ci 2276d4afb5ceSopenharmony_ci if (vhost) 2277d4afb5ceSopenharmony_ci lws_vhost_bind_wsi(vhost, wsi); 2278d4afb5ceSopenharmony_ci } else 2279d4afb5ceSopenharmony_ci lwsl_info("no host\n"); 2280d4afb5ceSopenharmony_ci 2281d4afb5ceSopenharmony_ci if ((!lwsi_role_h2(wsi) || !lwsi_role_server(wsi)) && 2282d4afb5ceSopenharmony_ci (!wsi->conn_stat_done)) 2283d4afb5ceSopenharmony_ci wsi->conn_stat_done = 1; 2284d4afb5ceSopenharmony_ci 2285d4afb5ceSopenharmony_ci /* check for unwelcome guests */ 2286d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 2287d4afb5ceSopenharmony_ci if (wsi->a.context->reject_service_keywords) { 2288d4afb5ceSopenharmony_ci const struct lws_protocol_vhost_options *rej = 2289d4afb5ceSopenharmony_ci wsi->a.context->reject_service_keywords; 2290d4afb5ceSopenharmony_ci char ua[384], *msg = NULL; 2291d4afb5ceSopenharmony_ci 2292d4afb5ceSopenharmony_ci if (lws_hdr_copy(wsi, ua, sizeof(ua) - 1, 2293d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_USER_AGENT) > 0) { 2294d4afb5ceSopenharmony_ci#ifdef LWS_WITH_ACCESS_LOG 2295d4afb5ceSopenharmony_ci char *uri_ptr = NULL; 2296d4afb5ceSopenharmony_ci int meth, uri_len; 2297d4afb5ceSopenharmony_ci#endif 2298d4afb5ceSopenharmony_ci ua[sizeof(ua) - 1] = '\0'; 2299d4afb5ceSopenharmony_ci while (rej) { 2300d4afb5ceSopenharmony_ci if (!strstr(ua, rej->name)) { 2301d4afb5ceSopenharmony_ci rej = rej->next; 2302d4afb5ceSopenharmony_ci continue; 2303d4afb5ceSopenharmony_ci } 2304d4afb5ceSopenharmony_ci 2305d4afb5ceSopenharmony_ci msg = strchr(rej->value, ' '); 2306d4afb5ceSopenharmony_ci if (msg) 2307d4afb5ceSopenharmony_ci msg++; 2308d4afb5ceSopenharmony_ci lws_return_http_status(wsi, 2309d4afb5ceSopenharmony_ci (unsigned int)atoi(rej->value), msg); 2310d4afb5ceSopenharmony_ci#ifdef LWS_WITH_ACCESS_LOG 2311d4afb5ceSopenharmony_ci meth = lws_http_get_uri_and_method(wsi, 2312d4afb5ceSopenharmony_ci &uri_ptr, &uri_len); 2313d4afb5ceSopenharmony_ci if (meth >= 0) 2314d4afb5ceSopenharmony_ci lws_prepare_access_log_info(wsi, 2315d4afb5ceSopenharmony_ci uri_ptr, uri_len, meth); 2316d4afb5ceSopenharmony_ci 2317d4afb5ceSopenharmony_ci /* wsi close will do the log */ 2318d4afb5ceSopenharmony_ci#endif 2319d4afb5ceSopenharmony_ci /* 2320d4afb5ceSopenharmony_ci * We don't want anything from 2321d4afb5ceSopenharmony_ci * this rejected guy. Follow 2322d4afb5ceSopenharmony_ci * the close flow, not the 2323d4afb5ceSopenharmony_ci * transaction complete flow. 2324d4afb5ceSopenharmony_ci */ 2325d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2326d4afb5ceSopenharmony_ci } 2327d4afb5ceSopenharmony_ci } 2328d4afb5ceSopenharmony_ci } 2329d4afb5ceSopenharmony_ci#endif 2330d4afb5ceSopenharmony_ci /* 2331d4afb5ceSopenharmony_ci * So he may have come to us requesting one or another kind 2332d4afb5ceSopenharmony_ci * of upgrade from http... but we may want to redirect him at 2333d4afb5ceSopenharmony_ci * http level. In that case, we need to check the redirect 2334d4afb5ceSopenharmony_ci * situation even though he's not actually wanting http and 2335d4afb5ceSopenharmony_ci * prioritize returning that if there is one. 2336d4afb5ceSopenharmony_ci */ 2337d4afb5ceSopenharmony_ci 2338d4afb5ceSopenharmony_ci { 2339d4afb5ceSopenharmony_ci const struct lws_http_mount *hit = NULL; 2340d4afb5ceSopenharmony_ci int uri_len = 0, ha, n; 2341d4afb5ceSopenharmony_ci char *uri_ptr = NULL; 2342d4afb5ceSopenharmony_ci 2343d4afb5ceSopenharmony_ci n = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len); 2344d4afb5ceSopenharmony_ci if (n >= 0) { 2345d4afb5ceSopenharmony_ci hit = lws_find_mount(wsi, uri_ptr, uri_len); 2346d4afb5ceSopenharmony_ci if (hit) { 2347d4afb5ceSopenharmony_ci n = lws_http_redirect_hit(pt, wsi, hit, uri_ptr, 2348d4afb5ceSopenharmony_ci uri_len, &ha); 2349d4afb5ceSopenharmony_ci if (ha) 2350d4afb5ceSopenharmony_ci return n; 2351d4afb5ceSopenharmony_ci } 2352d4afb5ceSopenharmony_ci } 2353d4afb5ceSopenharmony_ci } 2354d4afb5ceSopenharmony_ci 2355d4afb5ceSopenharmony_ci 2356d4afb5ceSopenharmony_ci 2357d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) { 2358d4afb5ceSopenharmony_ci lwsl_info("Changing to RAW mode\n"); 2359d4afb5ceSopenharmony_ci goto raw_transition; 2360d4afb5ceSopenharmony_ci } 2361d4afb5ceSopenharmony_ci 2362d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_PRE_WS_SERVING_ACCEPT); 2363d4afb5ceSopenharmony_ci lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); 2364d4afb5ceSopenharmony_ci 2365d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) { 2366d4afb5ceSopenharmony_ci 2367d4afb5ceSopenharmony_ci const char *up = lws_hdr_simple_ptr(wsi, 2368d4afb5ceSopenharmony_ci WSI_TOKEN_UPGRADE); 2369d4afb5ceSopenharmony_ci 2370d4afb5ceSopenharmony_ci if (strcasecmp(up, "websocket") && 2371d4afb5ceSopenharmony_ci strcasecmp(up, "h2c")) { 2372d4afb5ceSopenharmony_ci lwsl_info("Unknown upgrade '%s'\n", up); 2373d4afb5ceSopenharmony_ci 2374d4afb5ceSopenharmony_ci if (lws_return_http_status(wsi, 2375d4afb5ceSopenharmony_ci HTTP_STATUS_FORBIDDEN, NULL) || 2376d4afb5ceSopenharmony_ci lws_http_transaction_completed(wsi)) 2377d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2378d4afb5ceSopenharmony_ci } 2379d4afb5ceSopenharmony_ci 2380d4afb5ceSopenharmony_ci n = user_callback_handle_rxflow(wsi->a.protocol->callback, 2381d4afb5ceSopenharmony_ci wsi, LWS_CALLBACK_HTTP_CONFIRM_UPGRADE, 2382d4afb5ceSopenharmony_ci wsi->user_space, (char *)up, 0); 2383d4afb5ceSopenharmony_ci 2384d4afb5ceSopenharmony_ci /* just hang up? */ 2385d4afb5ceSopenharmony_ci 2386d4afb5ceSopenharmony_ci if (n < 0) 2387d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2388d4afb5ceSopenharmony_ci 2389d4afb5ceSopenharmony_ci /* callback returned headers already, do t_c? */ 2390d4afb5ceSopenharmony_ci 2391d4afb5ceSopenharmony_ci if (n > 0) { 2392d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 2393d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2394d4afb5ceSopenharmony_ci 2395d4afb5ceSopenharmony_ci /* continue on */ 2396d4afb5ceSopenharmony_ci 2397d4afb5ceSopenharmony_ci return 0; 2398d4afb5ceSopenharmony_ci } 2399d4afb5ceSopenharmony_ci 2400d4afb5ceSopenharmony_ci /* callback said 0, it was allowed */ 2401d4afb5ceSopenharmony_ci 2402d4afb5ceSopenharmony_ci if (wsi->a.vhost->options & 2403d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK && 2404d4afb5ceSopenharmony_ci lws_confirm_host_header(wsi)) 2405d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2406d4afb5ceSopenharmony_ci 2407d4afb5ceSopenharmony_ci if (!strcasecmp(up, "websocket")) { 2408d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) 2409d4afb5ceSopenharmony_ci lws_metrics_tag_wsi_add(wsi, "upg", "ws"); 2410d4afb5ceSopenharmony_ci lwsl_info("Upgrade to ws\n"); 2411d4afb5ceSopenharmony_ci goto upgrade_ws; 2412d4afb5ceSopenharmony_ci#endif 2413d4afb5ceSopenharmony_ci } 2414d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 2415d4afb5ceSopenharmony_ci if (!strcasecmp(up, "h2c")) { 2416d4afb5ceSopenharmony_ci lws_metrics_tag_wsi_add(wsi, "upg", "h2c"); 2417d4afb5ceSopenharmony_ci lwsl_info("Upgrade to h2c\n"); 2418d4afb5ceSopenharmony_ci goto upgrade_h2c; 2419d4afb5ceSopenharmony_ci } 2420d4afb5ceSopenharmony_ci#endif 2421d4afb5ceSopenharmony_ci } 2422d4afb5ceSopenharmony_ci 2423d4afb5ceSopenharmony_ci /* no upgrade ack... he remained as HTTP */ 2424d4afb5ceSopenharmony_ci 2425d4afb5ceSopenharmony_ci lwsl_info("%s: %s: No upgrade\n", __func__, lws_wsi_tag(wsi)); 2426d4afb5ceSopenharmony_ci 2427d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_ESTABLISHED); 2428d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 2429d4afb5ceSopenharmony_ci wsi->http.fop_fd = NULL; 2430d4afb5ceSopenharmony_ci#endif 2431d4afb5ceSopenharmony_ci 2432d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 2433d4afb5ceSopenharmony_ci lws_http_compression_validate(wsi); 2434d4afb5ceSopenharmony_ci#endif 2435d4afb5ceSopenharmony_ci 2436d4afb5ceSopenharmony_ci lwsl_debug("%s: %s: ah %p\n", __func__, lws_wsi_tag(wsi), 2437d4afb5ceSopenharmony_ci (void *)wsi->http.ah); 2438d4afb5ceSopenharmony_ci 2439d4afb5ceSopenharmony_ci n = lws_http_action(wsi); 2440d4afb5ceSopenharmony_ci 2441d4afb5ceSopenharmony_ci return n; 2442d4afb5ceSopenharmony_ci 2443d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 2444d4afb5ceSopenharmony_ciupgrade_h2c: 2445d4afb5ceSopenharmony_ci if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) { 2446d4afb5ceSopenharmony_ci lwsl_info("missing http2_settings\n"); 2447d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2448d4afb5ceSopenharmony_ci } 2449d4afb5ceSopenharmony_ci 2450d4afb5ceSopenharmony_ci lwsl_info("h2c upgrade...\n"); 2451d4afb5ceSopenharmony_ci 2452d4afb5ceSopenharmony_ci p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS); 2453d4afb5ceSopenharmony_ci /* convert the peer's HTTP-Settings */ 2454d4afb5ceSopenharmony_ci n = lws_b64_decode_string(p, tbuf, sizeof(tbuf)); 2455d4afb5ceSopenharmony_ci if (n < 0) { 2456d4afb5ceSopenharmony_ci lwsl_parser("HTTP2_SETTINGS too long\n"); 2457d4afb5ceSopenharmony_ci return 1; 2458d4afb5ceSopenharmony_ci } 2459d4afb5ceSopenharmony_ci 2460d4afb5ceSopenharmony_ci wsi->upgraded_to_http2 = 1; 2461d4afb5ceSopenharmony_ci 2462d4afb5ceSopenharmony_ci /* adopt the header info */ 2463d4afb5ceSopenharmony_ci 2464d4afb5ceSopenharmony_ci ah = wsi->http.ah; 2465d4afb5ceSopenharmony_ci lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE, 2466d4afb5ceSopenharmony_ci &role_ops_h2); 2467d4afb5ceSopenharmony_ci 2468d4afb5ceSopenharmony_ci /* http2 union member has http union struct at start */ 2469d4afb5ceSopenharmony_ci wsi->http.ah = ah; 2470d4afb5ceSopenharmony_ci 2471d4afb5ceSopenharmony_ci if (!wsi->h2.h2n) { 2472d4afb5ceSopenharmony_ci wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n"); 2473d4afb5ceSopenharmony_ci if (!wsi->h2.h2n) 2474d4afb5ceSopenharmony_ci return 1; 2475d4afb5ceSopenharmony_ci } 2476d4afb5ceSopenharmony_ci 2477d4afb5ceSopenharmony_ci lws_h2_init(wsi); 2478d4afb5ceSopenharmony_ci 2479d4afb5ceSopenharmony_ci /* HTTP2 union */ 2480d4afb5ceSopenharmony_ci 2481d4afb5ceSopenharmony_ci lws_h2_settings(wsi, &wsi->h2.h2n->peer_set, (uint8_t *)tbuf, n); 2482d4afb5ceSopenharmony_ci 2483d4afb5ceSopenharmony_ci if (lws_hpack_dynamic_size(wsi, (int)wsi->h2.h2n->peer_set.s[ 2484d4afb5ceSopenharmony_ci H2SET_HEADER_TABLE_SIZE])) 2485d4afb5ceSopenharmony_ci return 1; 2486d4afb5ceSopenharmony_ci 2487d4afb5ceSopenharmony_ci strcpy(tbuf, "HTTP/1.1 101 Switching Protocols\x0d\x0a" 2488d4afb5ceSopenharmony_ci "Connection: Upgrade\x0d\x0a" 2489d4afb5ceSopenharmony_ci "Upgrade: h2c\x0d\x0a\x0d\x0a"); 2490d4afb5ceSopenharmony_ci m = (int)strlen(tbuf); 2491d4afb5ceSopenharmony_ci n = lws_issue_raw(wsi, (unsigned char *)tbuf, (unsigned int)m); 2492d4afb5ceSopenharmony_ci if (n != m) { 2493d4afb5ceSopenharmony_ci lwsl_debug("http2 switch: ERROR writing to socket\n"); 2494d4afb5ceSopenharmony_ci return 1; 2495d4afb5ceSopenharmony_ci } 2496d4afb5ceSopenharmony_ci 2497d4afb5ceSopenharmony_ci return 0; 2498d4afb5ceSopenharmony_ci#endif 2499d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) 2500d4afb5ceSopenharmony_ciupgrade_ws: 2501d4afb5ceSopenharmony_ci if (lws_process_ws_upgrade(wsi)) 2502d4afb5ceSopenharmony_ci goto bail_nuke_ah; 2503d4afb5ceSopenharmony_ci 2504d4afb5ceSopenharmony_ci return 0; 2505d4afb5ceSopenharmony_ci#endif 2506d4afb5ceSopenharmony_ci } /* while all chars are handled */ 2507d4afb5ceSopenharmony_ci 2508d4afb5ceSopenharmony_ci return 0; 2509d4afb5ceSopenharmony_ci 2510d4afb5ceSopenharmony_cibail_nuke_ah: 2511d4afb5ceSopenharmony_ci /* drop the header info */ 2512d4afb5ceSopenharmony_ci lws_header_table_detach(wsi, 1); 2513d4afb5ceSopenharmony_ci 2514d4afb5ceSopenharmony_ci return 1; 2515d4afb5ceSopenharmony_ci} 2516d4afb5ceSopenharmony_ci#endif 2517d4afb5ceSopenharmony_ci 2518d4afb5ceSopenharmony_ciint LWS_WARN_UNUSED_RESULT 2519d4afb5ceSopenharmony_cilws_http_transaction_completed(struct lws *wsi) 2520d4afb5ceSopenharmony_ci{ 2521d4afb5ceSopenharmony_ci int n; 2522d4afb5ceSopenharmony_ci 2523d4afb5ceSopenharmony_ci if (wsi->http.cgi_transaction_complete) 2524d4afb5ceSopenharmony_ci return 0; 2525d4afb5ceSopenharmony_ci 2526d4afb5ceSopenharmony_ci if (lws_has_buffered_out(wsi) 2527d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 2528d4afb5ceSopenharmony_ci || wsi->http.comp_ctx.buflist_comp || 2529d4afb5ceSopenharmony_ci wsi->http.comp_ctx.may_have_more 2530d4afb5ceSopenharmony_ci#endif 2531d4afb5ceSopenharmony_ci ) { 2532d4afb5ceSopenharmony_ci /* 2533d4afb5ceSopenharmony_ci * ...so he tried to send something large as the http reply, 2534d4afb5ceSopenharmony_ci * it went as a partial, but he immediately said the 2535d4afb5ceSopenharmony_ci * transaction was completed. 2536d4afb5ceSopenharmony_ci * 2537d4afb5ceSopenharmony_ci * Defer the transaction completed until the last part of the 2538d4afb5ceSopenharmony_ci * partial is sent. 2539d4afb5ceSopenharmony_ci */ 2540d4afb5ceSopenharmony_ci lwsl_debug("%s: %s: deferring due to partial\n", __func__, 2541d4afb5ceSopenharmony_ci lws_wsi_tag(wsi)); 2542d4afb5ceSopenharmony_ci wsi->http.deferred_transaction_completed = 1; 2543d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 2544d4afb5ceSopenharmony_ci 2545d4afb5ceSopenharmony_ci return 0; 2546d4afb5ceSopenharmony_ci } 2547d4afb5ceSopenharmony_ci /* 2548d4afb5ceSopenharmony_ci * Are we finishing the transaction before we have consumed any body? 2549d4afb5ceSopenharmony_ci * 2550d4afb5ceSopenharmony_ci * For h1 this would kill keepalive pipelining, and for h2, considering 2551d4afb5ceSopenharmony_ci * it can extend over multiple DATA frames, it would kill the network 2552d4afb5ceSopenharmony_ci * connection. 2553d4afb5ceSopenharmony_ci */ 2554d4afb5ceSopenharmony_ci if (wsi->http.rx_content_length && wsi->http.rx_content_remain) { 2555d4afb5ceSopenharmony_ci /* 2556d4afb5ceSopenharmony_ci * are we already in LRS_DISCARD_BODY and didn't clear the 2557d4afb5ceSopenharmony_ci * remaining before trying to complete the transaction again? 2558d4afb5ceSopenharmony_ci */ 2559d4afb5ceSopenharmony_ci if (lwsi_state(wsi) == LRS_DISCARD_BODY) 2560d4afb5ceSopenharmony_ci return -1; 2561d4afb5ceSopenharmony_ci /* 2562d4afb5ceSopenharmony_ci * let's defer transaction completed processing until we 2563d4afb5ceSopenharmony_ci * discarded the remaining body 2564d4afb5ceSopenharmony_ci */ 2565d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_DISCARD_BODY); 2566d4afb5ceSopenharmony_ci 2567d4afb5ceSopenharmony_ci return 0; 2568d4afb5ceSopenharmony_ci } 2569d4afb5ceSopenharmony_ci 2570d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) 2571d4afb5ceSopenharmony_ci { 2572d4afb5ceSopenharmony_ci char tmp[10]; 2573d4afb5ceSopenharmony_ci 2574d4afb5ceSopenharmony_ci lws_snprintf(tmp, sizeof(tmp), "%u", wsi->http.response_code); 2575d4afb5ceSopenharmony_ci lws_metrics_tag_wsi_add(wsi, "status", tmp); 2576d4afb5ceSopenharmony_ci } 2577d4afb5ceSopenharmony_ci#endif 2578d4afb5ceSopenharmony_ci 2579d4afb5ceSopenharmony_ci lwsl_info("%s: %s\n", __func__, lws_wsi_tag(wsi)); 2580d4afb5ceSopenharmony_ci 2581d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 2582d4afb5ceSopenharmony_ci lws_http_compression_destroy(wsi); 2583d4afb5ceSopenharmony_ci#endif 2584d4afb5ceSopenharmony_ci lws_access_log(wsi); 2585d4afb5ceSopenharmony_ci 2586d4afb5ceSopenharmony_ci if (!wsi->hdr_parsing_completed 2587d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CGI) 2588d4afb5ceSopenharmony_ci && !wsi->http.cgi 2589d4afb5ceSopenharmony_ci#endif 2590d4afb5ceSopenharmony_ci ) { 2591d4afb5ceSopenharmony_ci char peer[64]; 2592d4afb5ceSopenharmony_ci 2593d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) 2594d4afb5ceSopenharmony_ci lws_get_peer_simple(wsi, peer, sizeof(peer) - 1); 2595d4afb5ceSopenharmony_ci#else 2596d4afb5ceSopenharmony_ci peer[0] = '\0'; 2597d4afb5ceSopenharmony_ci#endif 2598d4afb5ceSopenharmony_ci peer[sizeof(peer) - 1] = '\0'; 2599d4afb5ceSopenharmony_ci lwsl_info("%s: (from %s) ignoring, ah parsing incomplete\n", 2600d4afb5ceSopenharmony_ci __func__, peer); 2601d4afb5ceSopenharmony_ci return 0; 2602d4afb5ceSopenharmony_ci } 2603d4afb5ceSopenharmony_ci 2604d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CGI) 2605d4afb5ceSopenharmony_ci if (wsi->http.cgi) { 2606d4afb5ceSopenharmony_ci lwsl_debug("%s: cleaning cgi\n", __func__); 2607d4afb5ceSopenharmony_ci wsi->http.cgi_transaction_complete = 1; 2608d4afb5ceSopenharmony_ci lws_cgi_remove_and_kill(wsi); 2609d4afb5ceSopenharmony_ci lws_spawn_piped_destroy(&wsi->http.cgi->lsp); 2610d4afb5ceSopenharmony_ci lws_sul_cancel(&wsi->http.cgi->sul_grace); 2611d4afb5ceSopenharmony_ci 2612d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->http.cgi); 2613d4afb5ceSopenharmony_ci wsi->http.cgi_transaction_complete = 0; 2614d4afb5ceSopenharmony_ci } 2615d4afb5ceSopenharmony_ci#endif 2616d4afb5ceSopenharmony_ci 2617d4afb5ceSopenharmony_ci /* if we can't go back to accept new headers, drop the connection */ 2618d4afb5ceSopenharmony_ci if (wsi->mux_substream) 2619d4afb5ceSopenharmony_ci return 1; 2620d4afb5ceSopenharmony_ci 2621d4afb5ceSopenharmony_ci if (wsi->seen_zero_length_recv) 2622d4afb5ceSopenharmony_ci return 1; 2623d4afb5ceSopenharmony_ci 2624d4afb5ceSopenharmony_ci if (wsi->http.conn_type != HTTP_CONNECTION_KEEP_ALIVE) { 2625d4afb5ceSopenharmony_ci lwsl_info("%s: %s: close connection\n", __func__, lws_wsi_tag(wsi)); 2626d4afb5ceSopenharmony_ci return 1; 2627d4afb5ceSopenharmony_ci } 2628d4afb5ceSopenharmony_ci 2629d4afb5ceSopenharmony_ci if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[0], __func__)) 2630d4afb5ceSopenharmony_ci return 1; 2631d4afb5ceSopenharmony_ci 2632d4afb5ceSopenharmony_ci /* 2633d4afb5ceSopenharmony_ci * otherwise set ourselves up ready to go again, but because we have no 2634d4afb5ceSopenharmony_ci * idea about the wsi writability, we make put it in a holding state 2635d4afb5ceSopenharmony_ci * until we can verify POLLOUT. The part of this that confirms POLLOUT 2636d4afb5ceSopenharmony_ci * with no partials is in lws_server_socket_service() below. 2637d4afb5ceSopenharmony_ci */ 2638d4afb5ceSopenharmony_ci lwsl_debug("%s: %s: setting DEF_ACT from 0x%x: %p\n", __func__, 2639d4afb5ceSopenharmony_ci lws_wsi_tag(wsi), (int)wsi->wsistate, wsi->buflist); 2640d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_DEFERRING_ACTION); 2641d4afb5ceSopenharmony_ci wsi->http.tx_content_length = 0; 2642d4afb5ceSopenharmony_ci wsi->http.tx_content_remain = 0; 2643d4afb5ceSopenharmony_ci wsi->hdr_parsing_completed = 0; 2644d4afb5ceSopenharmony_ci wsi->sending_chunked = 0; 2645d4afb5ceSopenharmony_ci#ifdef LWS_WITH_ACCESS_LOG 2646d4afb5ceSopenharmony_ci wsi->http.access_log.sent = 0; 2647d4afb5ceSopenharmony_ci#endif 2648d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)) 2649d4afb5ceSopenharmony_ci if (lwsi_role_http(wsi) && lwsi_role_server(wsi) && 2650d4afb5ceSopenharmony_ci wsi->http.fop_fd != NULL) 2651d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 2652d4afb5ceSopenharmony_ci#endif 2653d4afb5ceSopenharmony_ci 2654d4afb5ceSopenharmony_ci n = NO_PENDING_TIMEOUT; 2655d4afb5ceSopenharmony_ci if (wsi->a.vhost->keepalive_timeout) 2656d4afb5ceSopenharmony_ci n = PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE; 2657d4afb5ceSopenharmony_ci lws_set_timeout(wsi, (enum pending_timeout)n, wsi->a.vhost->keepalive_timeout); 2658d4afb5ceSopenharmony_ci 2659d4afb5ceSopenharmony_ci /* 2660d4afb5ceSopenharmony_ci * We already know we are on http1.1 / keepalive and the next thing 2661d4afb5ceSopenharmony_ci * coming will be another header set. 2662d4afb5ceSopenharmony_ci * 2663d4afb5ceSopenharmony_ci * If there is no pending rx and we still have the ah, drop it and 2664d4afb5ceSopenharmony_ci * reacquire a new ah when the new headers start to arrive. (Otherwise 2665d4afb5ceSopenharmony_ci * we needlessly hog an ah indefinitely.) 2666d4afb5ceSopenharmony_ci * 2667d4afb5ceSopenharmony_ci * However if there is pending rx and we know from the keepalive state 2668d4afb5ceSopenharmony_ci * that is already at least the start of another header set, simply 2669d4afb5ceSopenharmony_ci * reset the existing header table and keep it. 2670d4afb5ceSopenharmony_ci */ 2671d4afb5ceSopenharmony_ci if (wsi->http.ah) { 2672d4afb5ceSopenharmony_ci // lws_buflist_describe(&wsi->buflist, wsi, __func__); 2673d4afb5ceSopenharmony_ci if (!lws_buflist_next_segment_len(&wsi->buflist, NULL)) { 2674d4afb5ceSopenharmony_ci lwsl_debug("%s: %s: nothing in buflist, detaching ah\n", 2675d4afb5ceSopenharmony_ci __func__, lws_wsi_tag(wsi)); 2676d4afb5ceSopenharmony_ci lws_header_table_detach(wsi, 1); 2677d4afb5ceSopenharmony_ci#ifdef LWS_WITH_TLS 2678d4afb5ceSopenharmony_ci /* 2679d4afb5ceSopenharmony_ci * additionally... if we are hogging an SSL instance 2680d4afb5ceSopenharmony_ci * with no pending pipelined headers (or ah now), and 2681d4afb5ceSopenharmony_ci * SSL is scarce, drop this connection without waiting 2682d4afb5ceSopenharmony_ci */ 2683d4afb5ceSopenharmony_ci 2684d4afb5ceSopenharmony_ci if (wsi->a.vhost->tls.use_ssl && 2685d4afb5ceSopenharmony_ci wsi->a.context->simultaneous_ssl_restriction && 2686d4afb5ceSopenharmony_ci wsi->a.context->simultaneous_ssl == 2687d4afb5ceSopenharmony_ci wsi->a.context->simultaneous_ssl_restriction) { 2688d4afb5ceSopenharmony_ci lwsl_info("%s: simultaneous_ssl_restriction\n", 2689d4afb5ceSopenharmony_ci __func__); 2690d4afb5ceSopenharmony_ci return 1; 2691d4afb5ceSopenharmony_ci } 2692d4afb5ceSopenharmony_ci#endif 2693d4afb5ceSopenharmony_ci } else { 2694d4afb5ceSopenharmony_ci lwsl_info("%s: %s: resetting/keeping ah as pipeline\n", 2695d4afb5ceSopenharmony_ci __func__, lws_wsi_tag(wsi)); 2696d4afb5ceSopenharmony_ci lws_header_table_reset(wsi, 0); 2697d4afb5ceSopenharmony_ci /* 2698d4afb5ceSopenharmony_ci * If we kept the ah, we should restrict the amount 2699d4afb5ceSopenharmony_ci * of time we are willing to keep it. Otherwise it 2700d4afb5ceSopenharmony_ci * will be bound the whole time the connection remains 2701d4afb5ceSopenharmony_ci * open. 2702d4afb5ceSopenharmony_ci */ 2703d4afb5ceSopenharmony_ci lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH, 2704d4afb5ceSopenharmony_ci wsi->a.vhost->keepalive_timeout); 2705d4afb5ceSopenharmony_ci } 2706d4afb5ceSopenharmony_ci /* If we're (re)starting on headers, need other implied init */ 2707d4afb5ceSopenharmony_ci if (wsi->http.ah) 2708d4afb5ceSopenharmony_ci wsi->http.ah->ues = URIES_IDLE; 2709d4afb5ceSopenharmony_ci 2710d4afb5ceSopenharmony_ci //lwsi_set_state(wsi, LRS_ESTABLISHED); // !!! 2711d4afb5ceSopenharmony_ci } else 2712d4afb5ceSopenharmony_ci if (lws_buflist_next_segment_len(&wsi->buflist, NULL)) 2713d4afb5ceSopenharmony_ci if (lws_header_table_attach(wsi, 0)) 2714d4afb5ceSopenharmony_ci lwsl_debug("acquired ah\n"); 2715d4afb5ceSopenharmony_ci 2716d4afb5ceSopenharmony_ci lwsl_debug("%s: %s: keep-alive await new transaction (state 0x%x)\n", 2717d4afb5ceSopenharmony_ci __func__, lws_wsi_tag(wsi), (int)wsi->wsistate); 2718d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 2719d4afb5ceSopenharmony_ci 2720d4afb5ceSopenharmony_ci return 0; 2721d4afb5ceSopenharmony_ci} 2722d4afb5ceSopenharmony_ci 2723d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 2724d4afb5ceSopenharmony_ciint 2725d4afb5ceSopenharmony_cilws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, 2726d4afb5ceSopenharmony_ci const char *other_headers, int other_headers_len) 2727d4afb5ceSopenharmony_ci{ 2728d4afb5ceSopenharmony_ci struct lws_context *context = lws_get_context(wsi); 2729d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 2730d4afb5ceSopenharmony_ci unsigned char *response = pt->serv_buf + LWS_PRE; 2731d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 2732d4afb5ceSopenharmony_ci struct lws_range_parsing *rp = &wsi->http.range; 2733d4afb5ceSopenharmony_ci#endif 2734d4afb5ceSopenharmony_ci int ret = 0, cclen = 8, n = HTTP_STATUS_OK; 2735d4afb5ceSopenharmony_ci char cache_control[50], *cc = "no-store"; 2736d4afb5ceSopenharmony_ci lws_fop_flags_t fflags = LWS_O_RDONLY; 2737d4afb5ceSopenharmony_ci const struct lws_plat_file_ops *fops; 2738d4afb5ceSopenharmony_ci lws_filepos_t total_content_length; 2739d4afb5ceSopenharmony_ci unsigned char *p = response; 2740d4afb5ceSopenharmony_ci unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE; 2741d4afb5ceSopenharmony_ci const char *vpath; 2742d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 2743d4afb5ceSopenharmony_ci int ranges; 2744d4afb5ceSopenharmony_ci#endif 2745d4afb5ceSopenharmony_ci 2746d4afb5ceSopenharmony_ci if (wsi->handling_404) 2747d4afb5ceSopenharmony_ci n = HTTP_STATUS_NOT_FOUND; 2748d4afb5ceSopenharmony_ci 2749d4afb5ceSopenharmony_ci /* 2750d4afb5ceSopenharmony_ci * We either call the platform fops .open with first arg platform fops, 2751d4afb5ceSopenharmony_ci * or we call fops_zip .open with first arg platform fops, and fops_zip 2752d4afb5ceSopenharmony_ci * open will decide whether to switch to fops_zip or stay with fops_def. 2753d4afb5ceSopenharmony_ci * 2754d4afb5ceSopenharmony_ci * If wsi->http.fop_fd is already set, the caller already opened it 2755d4afb5ceSopenharmony_ci */ 2756d4afb5ceSopenharmony_ci if (!wsi->http.fop_fd) { 2757d4afb5ceSopenharmony_ci fops = lws_vfs_select_fops(wsi->a.context->fops, file, &vpath); 2758d4afb5ceSopenharmony_ci fflags |= lws_vfs_prepare_flags(wsi); 2759d4afb5ceSopenharmony_ci wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->a.context->fops, 2760d4afb5ceSopenharmony_ci file, vpath, &fflags); 2761d4afb5ceSopenharmony_ci if (!wsi->http.fop_fd) { 2762d4afb5ceSopenharmony_ci lwsl_info("%s: Unable to open: '%s': errno %d\n", 2763d4afb5ceSopenharmony_ci __func__, file, errno); 2764d4afb5ceSopenharmony_ci if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, 2765d4afb5ceSopenharmony_ci NULL)) 2766d4afb5ceSopenharmony_ci return -1; 2767d4afb5ceSopenharmony_ci return !wsi->mux_substream; 2768d4afb5ceSopenharmony_ci } 2769d4afb5ceSopenharmony_ci } 2770d4afb5ceSopenharmony_ci 2771d4afb5ceSopenharmony_ci /* 2772d4afb5ceSopenharmony_ci * Caution... wsi->http.fop_fd is live from here 2773d4afb5ceSopenharmony_ci */ 2774d4afb5ceSopenharmony_ci 2775d4afb5ceSopenharmony_ci wsi->http.filelen = lws_vfs_get_length(wsi->http.fop_fd); 2776d4afb5ceSopenharmony_ci total_content_length = wsi->http.filelen; 2777d4afb5ceSopenharmony_ci 2778d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 2779d4afb5ceSopenharmony_ci ranges = lws_ranges_init(wsi, rp, wsi->http.filelen); 2780d4afb5ceSopenharmony_ci 2781d4afb5ceSopenharmony_ci lwsl_debug("Range count %d\n", ranges); 2782d4afb5ceSopenharmony_ci /* 2783d4afb5ceSopenharmony_ci * no ranges -> 200; 2784d4afb5ceSopenharmony_ci * 1 range -> 206 + Content-Type: normal; Content-Range; 2785d4afb5ceSopenharmony_ci * more -> 206 + Content-Type: multipart/byteranges 2786d4afb5ceSopenharmony_ci * Repeat the true Content-Type in each multipart header 2787d4afb5ceSopenharmony_ci * along with Content-Range 2788d4afb5ceSopenharmony_ci */ 2789d4afb5ceSopenharmony_ci if (ranges < 0) { 2790d4afb5ceSopenharmony_ci /* it means he expressed a range in Range:, but it was illegal */ 2791d4afb5ceSopenharmony_ci lws_return_http_status(wsi, 2792d4afb5ceSopenharmony_ci HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, NULL); 2793d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 2794d4afb5ceSopenharmony_ci goto bail; /* <0 means just hang up */ 2795d4afb5ceSopenharmony_ci 2796d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 2797d4afb5ceSopenharmony_ci 2798d4afb5ceSopenharmony_ci return 0; /* == 0 means we did the transaction complete */ 2799d4afb5ceSopenharmony_ci } 2800d4afb5ceSopenharmony_ci if (ranges) 2801d4afb5ceSopenharmony_ci n = HTTP_STATUS_PARTIAL_CONTENT; 2802d4afb5ceSopenharmony_ci#endif 2803d4afb5ceSopenharmony_ci 2804d4afb5ceSopenharmony_ci if (lws_add_http_header_status(wsi, (unsigned int)n, &p, end)) 2805d4afb5ceSopenharmony_ci goto bail; 2806d4afb5ceSopenharmony_ci 2807d4afb5ceSopenharmony_ci if ((wsi->http.fop_fd->flags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | 2808d4afb5ceSopenharmony_ci LWS_FOP_FLAG_COMPR_IS_GZIP)) == 2809d4afb5ceSopenharmony_ci (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) { 2810d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 2811d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_ENCODING, 2812d4afb5ceSopenharmony_ci (unsigned char *)"gzip", 4, &p, end)) 2813d4afb5ceSopenharmony_ci goto bail; 2814d4afb5ceSopenharmony_ci lwsl_info("file is being provided in gzip\n"); 2815d4afb5ceSopenharmony_ci } 2816d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 2817d4afb5ceSopenharmony_ci else { 2818d4afb5ceSopenharmony_ci /* 2819d4afb5ceSopenharmony_ci * if we know its very compressible, and we can use 2820d4afb5ceSopenharmony_ci * compression, then use the most preferred compression 2821d4afb5ceSopenharmony_ci * method that the client said he will accept 2822d4afb5ceSopenharmony_ci */ 2823d4afb5ceSopenharmony_ci 2824d4afb5ceSopenharmony_ci if (!wsi->interpreting && ( 2825d4afb5ceSopenharmony_ci !strncmp(content_type, "text/", 5) || 2826d4afb5ceSopenharmony_ci !strcmp(content_type, "application/javascript") || 2827d4afb5ceSopenharmony_ci !strcmp(content_type, "image/svg+xml"))) 2828d4afb5ceSopenharmony_ci lws_http_compression_apply(wsi, NULL, &p, end, 0); 2829d4afb5ceSopenharmony_ci } 2830d4afb5ceSopenharmony_ci#endif 2831d4afb5ceSopenharmony_ci 2832d4afb5ceSopenharmony_ci if ( 2833d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 2834d4afb5ceSopenharmony_ci ranges < 2 && 2835d4afb5ceSopenharmony_ci#endif 2836d4afb5ceSopenharmony_ci content_type && content_type[0]) 2837d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 2838d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_TYPE, 2839d4afb5ceSopenharmony_ci (unsigned char *)content_type, 2840d4afb5ceSopenharmony_ci (int)strlen(content_type), 2841d4afb5ceSopenharmony_ci &p, end)) 2842d4afb5ceSopenharmony_ci goto bail; 2843d4afb5ceSopenharmony_ci 2844d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 2845d4afb5ceSopenharmony_ci if (ranges >= 2) { /* multipart byteranges */ 2846d4afb5ceSopenharmony_ci lws_strncpy(wsi->http.multipart_content_type, content_type, 2847d4afb5ceSopenharmony_ci sizeof(wsi->http.multipart_content_type)); 2848d4afb5ceSopenharmony_ci 2849d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 2850d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_TYPE, 2851d4afb5ceSopenharmony_ci (unsigned char *) 2852d4afb5ceSopenharmony_ci "multipart/byteranges; " 2853d4afb5ceSopenharmony_ci "boundary=_lws", 2854d4afb5ceSopenharmony_ci 20, &p, end)) 2855d4afb5ceSopenharmony_ci goto bail; 2856d4afb5ceSopenharmony_ci 2857d4afb5ceSopenharmony_ci /* 2858d4afb5ceSopenharmony_ci * our overall content length has to include 2859d4afb5ceSopenharmony_ci * 2860d4afb5ceSopenharmony_ci * - (n + 1) x "_lws\r\n" 2861d4afb5ceSopenharmony_ci * - n x Content-Type: xxx/xxx\r\n 2862d4afb5ceSopenharmony_ci * - n x Content-Range: bytes xxx-yyy/zzz\r\n 2863d4afb5ceSopenharmony_ci * - n x /r/n 2864d4afb5ceSopenharmony_ci * - the actual payloads (aggregated in rp->agg) 2865d4afb5ceSopenharmony_ci * 2866d4afb5ceSopenharmony_ci * Precompute it for the main response header 2867d4afb5ceSopenharmony_ci */ 2868d4afb5ceSopenharmony_ci 2869d4afb5ceSopenharmony_ci total_content_length = (lws_filepos_t)rp->agg + 2870d4afb5ceSopenharmony_ci 6 /* final _lws\r\n */; 2871d4afb5ceSopenharmony_ci 2872d4afb5ceSopenharmony_ci lws_ranges_reset(rp); 2873d4afb5ceSopenharmony_ci while (lws_ranges_next(rp)) { 2874d4afb5ceSopenharmony_ci n = lws_snprintf(cache_control, sizeof(cache_control), 2875d4afb5ceSopenharmony_ci "bytes %llu-%llu/%llu", 2876d4afb5ceSopenharmony_ci rp->start, rp->end, rp->extent); 2877d4afb5ceSopenharmony_ci 2878d4afb5ceSopenharmony_ci total_content_length = total_content_length + 2879d4afb5ceSopenharmony_ci (lws_filepos_t)( 2880d4afb5ceSopenharmony_ci 6 /* header _lws\r\n */ + 2881d4afb5ceSopenharmony_ci /* Content-Type: xxx/xxx\r\n */ 2882d4afb5ceSopenharmony_ci 14 + (int)strlen(content_type) + 2 + 2883d4afb5ceSopenharmony_ci /* Content-Range: xxxx\r\n */ 2884d4afb5ceSopenharmony_ci 15 + n + 2 + 2885d4afb5ceSopenharmony_ci 2); /* /r/n */ 2886d4afb5ceSopenharmony_ci } 2887d4afb5ceSopenharmony_ci 2888d4afb5ceSopenharmony_ci lws_ranges_reset(rp); 2889d4afb5ceSopenharmony_ci lws_ranges_next(rp); 2890d4afb5ceSopenharmony_ci } 2891d4afb5ceSopenharmony_ci 2892d4afb5ceSopenharmony_ci if (ranges == 1) { 2893d4afb5ceSopenharmony_ci total_content_length = (lws_filepos_t)rp->agg; 2894d4afb5ceSopenharmony_ci n = lws_snprintf(cache_control, sizeof(cache_control), 2895d4afb5ceSopenharmony_ci "bytes %llu-%llu/%llu", 2896d4afb5ceSopenharmony_ci rp->start, rp->end, rp->extent); 2897d4afb5ceSopenharmony_ci 2898d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 2899d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_RANGE, 2900d4afb5ceSopenharmony_ci (unsigned char *)cache_control, 2901d4afb5ceSopenharmony_ci n, &p, end)) 2902d4afb5ceSopenharmony_ci goto bail; 2903d4afb5ceSopenharmony_ci } 2904d4afb5ceSopenharmony_ci 2905d4afb5ceSopenharmony_ci wsi->http.range.inside = 0; 2906d4afb5ceSopenharmony_ci 2907d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT_RANGES, 2908d4afb5ceSopenharmony_ci (unsigned char *)"bytes", 5, &p, end)) 2909d4afb5ceSopenharmony_ci goto bail; 2910d4afb5ceSopenharmony_ci#endif 2911d4afb5ceSopenharmony_ci 2912d4afb5ceSopenharmony_ci if (!wsi->mux_substream) { 2913d4afb5ceSopenharmony_ci /* for http/1.1 ... */ 2914d4afb5ceSopenharmony_ci if (!wsi->sending_chunked 2915d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 2916d4afb5ceSopenharmony_ci && !wsi->http.lcs 2917d4afb5ceSopenharmony_ci#endif 2918d4afb5ceSopenharmony_ci ) { 2919d4afb5ceSopenharmony_ci /* ... if not already using chunked and not using an 2920d4afb5ceSopenharmony_ci * http compression translation, then send the naive 2921d4afb5ceSopenharmony_ci * content length 2922d4afb5ceSopenharmony_ci */ 2923d4afb5ceSopenharmony_ci if (lws_add_http_header_content_length(wsi, 2924d4afb5ceSopenharmony_ci total_content_length, &p, end)) 2925d4afb5ceSopenharmony_ci goto bail; 2926d4afb5ceSopenharmony_ci } else { 2927d4afb5ceSopenharmony_ci 2928d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 2929d4afb5ceSopenharmony_ci if (wsi->http.lcs) { 2930d4afb5ceSopenharmony_ci 2931d4afb5ceSopenharmony_ci /* ...otherwise, for http 1 it must go chunked. 2932d4afb5ceSopenharmony_ci * For the compression case, the reason is we 2933d4afb5ceSopenharmony_ci * compress on the fly and do not know the 2934d4afb5ceSopenharmony_ci * compressed content-length until it has all 2935d4afb5ceSopenharmony_ci * been sent. Http/1.1 pipelining must be able 2936d4afb5ceSopenharmony_ci * to know where the transaction boundaries are 2937d4afb5ceSopenharmony_ci * ... so chunking... 2938d4afb5ceSopenharmony_ci */ 2939d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 2940d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_TRANSFER_ENCODING, 2941d4afb5ceSopenharmony_ci (unsigned char *)"chunked", 7, 2942d4afb5ceSopenharmony_ci &p, end)) 2943d4afb5ceSopenharmony_ci goto bail; 2944d4afb5ceSopenharmony_ci 2945d4afb5ceSopenharmony_ci /* 2946d4afb5ceSopenharmony_ci * ...this is fun, isn't it :-) For h1 that is 2947d4afb5ceSopenharmony_ci * using an http compression translation, the 2948d4afb5ceSopenharmony_ci * compressor must chunk its output privately. 2949d4afb5ceSopenharmony_ci * 2950d4afb5ceSopenharmony_ci * h2 doesn't need (or support) any of this 2951d4afb5ceSopenharmony_ci * crap. 2952d4afb5ceSopenharmony_ci */ 2953d4afb5ceSopenharmony_ci lwsl_debug("setting chunking\n"); 2954d4afb5ceSopenharmony_ci wsi->http.comp_ctx.chunking = 1; 2955d4afb5ceSopenharmony_ci } 2956d4afb5ceSopenharmony_ci#endif 2957d4afb5ceSopenharmony_ci } 2958d4afb5ceSopenharmony_ci } 2959d4afb5ceSopenharmony_ci 2960d4afb5ceSopenharmony_ci if (wsi->cache_secs && wsi->cache_reuse) { 2961d4afb5ceSopenharmony_ci if (!wsi->cache_revalidate) { 2962d4afb5ceSopenharmony_ci cc = cache_control; 2963d4afb5ceSopenharmony_ci cclen = sprintf(cache_control, "%s, max-age=%u", 2964d4afb5ceSopenharmony_ci intermediates[wsi->cache_intermediaries], 2965d4afb5ceSopenharmony_ci wsi->cache_secs); 2966d4afb5ceSopenharmony_ci } else { 2967d4afb5ceSopenharmony_ci cc = cache_control; 2968d4afb5ceSopenharmony_ci cclen = sprintf(cache_control, 2969d4afb5ceSopenharmony_ci "must-revalidate, %s, max-age=%u", 2970d4afb5ceSopenharmony_ci intermediates[wsi->cache_intermediaries], 2971d4afb5ceSopenharmony_ci wsi->cache_secs); 2972d4afb5ceSopenharmony_ci 2973d4afb5ceSopenharmony_ci } 2974d4afb5ceSopenharmony_ci } 2975d4afb5ceSopenharmony_ci 2976d4afb5ceSopenharmony_ci /* Only add cache control if its not specified by any other_headers. */ 2977d4afb5ceSopenharmony_ci if (!other_headers || 2978d4afb5ceSopenharmony_ci (!strstr(other_headers, "cache-control") && 2979d4afb5ceSopenharmony_ci !strstr(other_headers, "Cache-Control"))) { 2980d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 2981d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CACHE_CONTROL, 2982d4afb5ceSopenharmony_ci (unsigned char *)cc, cclen, &p, end)) 2983d4afb5ceSopenharmony_ci goto bail; 2984d4afb5ceSopenharmony_ci } 2985d4afb5ceSopenharmony_ci 2986d4afb5ceSopenharmony_ci if (other_headers) { 2987d4afb5ceSopenharmony_ci if ((end - p) < other_headers_len) 2988d4afb5ceSopenharmony_ci goto bail; 2989d4afb5ceSopenharmony_ci memcpy(p, other_headers, (unsigned int)other_headers_len); 2990d4afb5ceSopenharmony_ci p += other_headers_len; 2991d4afb5ceSopenharmony_ci } 2992d4afb5ceSopenharmony_ci 2993d4afb5ceSopenharmony_ci if (lws_finalize_http_header(wsi, &p, end)) 2994d4afb5ceSopenharmony_ci goto bail; 2995d4afb5ceSopenharmony_ci 2996d4afb5ceSopenharmony_ci ret = lws_write(wsi, response, lws_ptr_diff_size_t(p, response), LWS_WRITE_HTTP_HEADERS); 2997d4afb5ceSopenharmony_ci if (ret != (p - response)) { 2998d4afb5ceSopenharmony_ci lwsl_err("_write returned %d from %ld\n", ret, 2999d4afb5ceSopenharmony_ci (long)(p - response)); 3000d4afb5ceSopenharmony_ci goto bail; 3001d4afb5ceSopenharmony_ci } 3002d4afb5ceSopenharmony_ci 3003d4afb5ceSopenharmony_ci wsi->http.filepos = 0; 3004d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_ISSUING_FILE); 3005d4afb5ceSopenharmony_ci 3006d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_HEAD_URI)) { 3007d4afb5ceSopenharmony_ci /* we do not emit the body */ 3008d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 3009d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 3010d4afb5ceSopenharmony_ci goto bail; 3011d4afb5ceSopenharmony_ci 3012d4afb5ceSopenharmony_ci return 0; 3013d4afb5ceSopenharmony_ci } 3014d4afb5ceSopenharmony_ci 3015d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 3016d4afb5ceSopenharmony_ci 3017d4afb5ceSopenharmony_ci return 0; 3018d4afb5ceSopenharmony_ci 3019d4afb5ceSopenharmony_cibail: 3020d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 3021d4afb5ceSopenharmony_ci 3022d4afb5ceSopenharmony_ci return -1; 3023d4afb5ceSopenharmony_ci} 3024d4afb5ceSopenharmony_ci#endif 3025d4afb5ceSopenharmony_ci 3026d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS) 3027d4afb5ceSopenharmony_ci 3028d4afb5ceSopenharmony_ciint lws_serve_http_file_fragment(struct lws *wsi) 3029d4afb5ceSopenharmony_ci{ 3030d4afb5ceSopenharmony_ci struct lws_context *context = wsi->a.context; 3031d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 3032d4afb5ceSopenharmony_ci struct lws_process_html_args args; 3033d4afb5ceSopenharmony_ci lws_filepos_t amount, poss; 3034d4afb5ceSopenharmony_ci unsigned char *p, *pstart; 3035d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 3036d4afb5ceSopenharmony_ci unsigned char finished = 0; 3037d4afb5ceSopenharmony_ci#endif 3038d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 3039d4afb5ceSopenharmony_ci struct lws *nwsi; 3040d4afb5ceSopenharmony_ci#endif 3041d4afb5ceSopenharmony_ci int n, m; 3042d4afb5ceSopenharmony_ci 3043d4afb5ceSopenharmony_ci lwsl_debug("wsi->mux_substream %d\n", wsi->mux_substream); 3044d4afb5ceSopenharmony_ci 3045d4afb5ceSopenharmony_ci do { 3046d4afb5ceSopenharmony_ci 3047d4afb5ceSopenharmony_ci /* priority 1: buffered output */ 3048d4afb5ceSopenharmony_ci 3049d4afb5ceSopenharmony_ci if (lws_has_buffered_out(wsi)) { 3050d4afb5ceSopenharmony_ci if (lws_issue_raw(wsi, NULL, 0) < 0) { 3051d4afb5ceSopenharmony_ci lwsl_info("%s: closing\n", __func__); 3052d4afb5ceSopenharmony_ci goto file_had_it; 3053d4afb5ceSopenharmony_ci } 3054d4afb5ceSopenharmony_ci break; 3055d4afb5ceSopenharmony_ci } 3056d4afb5ceSopenharmony_ci 3057d4afb5ceSopenharmony_ci /* priority 2: buffered pre-compression-transform */ 3058d4afb5ceSopenharmony_ci 3059d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 3060d4afb5ceSopenharmony_ci if (wsi->http.comp_ctx.buflist_comp || 3061d4afb5ceSopenharmony_ci wsi->http.comp_ctx.may_have_more) { 3062d4afb5ceSopenharmony_ci enum lws_write_protocol wp = LWS_WRITE_HTTP; 3063d4afb5ceSopenharmony_ci 3064d4afb5ceSopenharmony_ci lwsl_info("%s: completing comp partial (buflist %p, may %d)\n", 3065d4afb5ceSopenharmony_ci __func__, wsi->http.comp_ctx.buflist_comp, 3066d4afb5ceSopenharmony_ci wsi->http.comp_ctx.may_have_more); 3067d4afb5ceSopenharmony_ci 3068d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) && 3069d4afb5ceSopenharmony_ci lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol). 3070d4afb5ceSopenharmony_ci write_role_protocol(wsi, NULL, 0, &wp) < 0) { 3071d4afb5ceSopenharmony_ci lwsl_info("%s signalling to close\n", __func__); 3072d4afb5ceSopenharmony_ci goto file_had_it; 3073d4afb5ceSopenharmony_ci } 3074d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 3075d4afb5ceSopenharmony_ci 3076d4afb5ceSopenharmony_ci break; 3077d4afb5ceSopenharmony_ci } 3078d4afb5ceSopenharmony_ci#endif 3079d4afb5ceSopenharmony_ci 3080d4afb5ceSopenharmony_ci if (wsi->http.filepos == wsi->http.filelen) 3081d4afb5ceSopenharmony_ci goto all_sent; 3082d4afb5ceSopenharmony_ci 3083d4afb5ceSopenharmony_ci n = 0; 3084d4afb5ceSopenharmony_ci p = pstart = pt->serv_buf + LWS_H2_FRAME_HEADER_LENGTH; 3085d4afb5ceSopenharmony_ci 3086d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 3087d4afb5ceSopenharmony_ci if (wsi->http.range.count_ranges && !wsi->http.range.inside) { 3088d4afb5ceSopenharmony_ci 3089d4afb5ceSopenharmony_ci lwsl_notice("%s: doing range start %llu\n", __func__, 3090d4afb5ceSopenharmony_ci wsi->http.range.start); 3091d4afb5ceSopenharmony_ci 3092d4afb5ceSopenharmony_ci if ((long long)lws_vfs_file_seek_cur(wsi->http.fop_fd, 3093d4afb5ceSopenharmony_ci (lws_fileofs_t)wsi->http.range.start - 3094d4afb5ceSopenharmony_ci (lws_fileofs_t)wsi->http.filepos) < 0) 3095d4afb5ceSopenharmony_ci goto file_had_it; 3096d4afb5ceSopenharmony_ci 3097d4afb5ceSopenharmony_ci wsi->http.filepos = wsi->http.range.start; 3098d4afb5ceSopenharmony_ci 3099d4afb5ceSopenharmony_ci if (wsi->http.range.count_ranges > 1) { 3100d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, 3101d4afb5ceSopenharmony_ci context->pt_serv_buf_size - 3102d4afb5ceSopenharmony_ci LWS_H2_FRAME_HEADER_LENGTH, 3103d4afb5ceSopenharmony_ci "_lws\x0d\x0a" 3104d4afb5ceSopenharmony_ci "Content-Type: %s\x0d\x0a" 3105d4afb5ceSopenharmony_ci "Content-Range: bytes " 3106d4afb5ceSopenharmony_ci "%llu-%llu/%llu\x0d\x0a" 3107d4afb5ceSopenharmony_ci "\x0d\x0a", 3108d4afb5ceSopenharmony_ci wsi->http.multipart_content_type, 3109d4afb5ceSopenharmony_ci wsi->http.range.start, 3110d4afb5ceSopenharmony_ci wsi->http.range.end, 3111d4afb5ceSopenharmony_ci wsi->http.range.extent); 3112d4afb5ceSopenharmony_ci p += n; 3113d4afb5ceSopenharmony_ci } 3114d4afb5ceSopenharmony_ci 3115d4afb5ceSopenharmony_ci wsi->http.range.budget = wsi->http.range.end - 3116d4afb5ceSopenharmony_ci wsi->http.range.start + 1; 3117d4afb5ceSopenharmony_ci wsi->http.range.inside = 1; 3118d4afb5ceSopenharmony_ci } 3119d4afb5ceSopenharmony_ci#endif 3120d4afb5ceSopenharmony_ci 3121d4afb5ceSopenharmony_ci poss = context->pt_serv_buf_size; 3122d4afb5ceSopenharmony_ci 3123d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 3124d4afb5ceSopenharmony_ci /* 3125d4afb5ceSopenharmony_ci * If it's h2, restrict any lump that we are sending to the 3126d4afb5ceSopenharmony_ci * max h2 frame size the peer indicated he could handle in 3127d4afb5ceSopenharmony_ci * his SETTINGS 3128d4afb5ceSopenharmony_ci */ 3129d4afb5ceSopenharmony_ci nwsi = lws_get_network_wsi(wsi); 3130d4afb5ceSopenharmony_ci if (nwsi->h2.h2n && 3131d4afb5ceSopenharmony_ci poss > (lws_filepos_t)nwsi->h2.h2n->peer_set.s[H2SET_MAX_FRAME_SIZE]) 3132d4afb5ceSopenharmony_ci poss = (lws_filepos_t)nwsi->h2.h2n->peer_set.s[H2SET_MAX_FRAME_SIZE]; 3133d4afb5ceSopenharmony_ci#endif 3134d4afb5ceSopenharmony_ci poss = poss - (lws_filepos_t)(n + LWS_H2_FRAME_HEADER_LENGTH); 3135d4afb5ceSopenharmony_ci 3136d4afb5ceSopenharmony_ci if (wsi->http.tx_content_length) 3137d4afb5ceSopenharmony_ci if (poss > wsi->http.tx_content_remain) 3138d4afb5ceSopenharmony_ci poss = wsi->http.tx_content_remain; 3139d4afb5ceSopenharmony_ci 3140d4afb5ceSopenharmony_ci /* 3141d4afb5ceSopenharmony_ci * If there is a hint about how much we will do well to send at 3142d4afb5ceSopenharmony_ci * one time, restrict ourselves to only trying to send that. 3143d4afb5ceSopenharmony_ci */ 3144d4afb5ceSopenharmony_ci if (wsi->a.protocol->tx_packet_size && 3145d4afb5ceSopenharmony_ci poss > wsi->a.protocol->tx_packet_size) 3146d4afb5ceSopenharmony_ci poss = wsi->a.protocol->tx_packet_size; 3147d4afb5ceSopenharmony_ci 3148d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit)) { 3149d4afb5ceSopenharmony_ci lws_filepos_t txc = (unsigned int)lws_rops_func_fidx(wsi->role_ops, 3150d4afb5ceSopenharmony_ci LWS_ROPS_tx_credit). 3151d4afb5ceSopenharmony_ci tx_credit(wsi, LWSTXCR_US_TO_PEER, 0); 3152d4afb5ceSopenharmony_ci 3153d4afb5ceSopenharmony_ci if (!txc) { 3154d4afb5ceSopenharmony_ci /* 3155d4afb5ceSopenharmony_ci * We shouldn't've been able to get the 3156d4afb5ceSopenharmony_ci * WRITEABLE if we are skint 3157d4afb5ceSopenharmony_ci */ 3158d4afb5ceSopenharmony_ci lwsl_notice("%s: %s: no tx credit\n", __func__, 3159d4afb5ceSopenharmony_ci lws_wsi_tag(wsi)); 3160d4afb5ceSopenharmony_ci 3161d4afb5ceSopenharmony_ci return 0; 3162d4afb5ceSopenharmony_ci } 3163d4afb5ceSopenharmony_ci if (txc < poss) 3164d4afb5ceSopenharmony_ci poss = txc; 3165d4afb5ceSopenharmony_ci 3166d4afb5ceSopenharmony_ci /* 3167d4afb5ceSopenharmony_ci * Tracking consumption of the actual payload amount 3168d4afb5ceSopenharmony_ci * will be handled when the role data frame is sent... 3169d4afb5ceSopenharmony_ci */ 3170d4afb5ceSopenharmony_ci } 3171d4afb5ceSopenharmony_ci 3172d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 3173d4afb5ceSopenharmony_ci if (wsi->http.range.count_ranges) { 3174d4afb5ceSopenharmony_ci if (wsi->http.range.count_ranges > 1) 3175d4afb5ceSopenharmony_ci poss -= 7; /* allow for final boundary */ 3176d4afb5ceSopenharmony_ci if (poss > wsi->http.range.budget) 3177d4afb5ceSopenharmony_ci poss = wsi->http.range.budget; 3178d4afb5ceSopenharmony_ci } 3179d4afb5ceSopenharmony_ci#endif 3180d4afb5ceSopenharmony_ci if (wsi->sending_chunked) { 3181d4afb5ceSopenharmony_ci /* we need to drop the chunk size in here */ 3182d4afb5ceSopenharmony_ci p += 10; 3183d4afb5ceSopenharmony_ci /* allow for the chunk to grow by 128 in translation */ 3184d4afb5ceSopenharmony_ci poss -= 10 + 128; 3185d4afb5ceSopenharmony_ci } 3186d4afb5ceSopenharmony_ci 3187d4afb5ceSopenharmony_ci amount = 0; 3188d4afb5ceSopenharmony_ci if (lws_vfs_file_read(wsi->http.fop_fd, &amount, p, poss) < 0) 3189d4afb5ceSopenharmony_ci goto file_had_it; /* caller will close */ 3190d4afb5ceSopenharmony_ci 3191d4afb5ceSopenharmony_ci if (wsi->sending_chunked) 3192d4afb5ceSopenharmony_ci n = (int)amount; 3193d4afb5ceSopenharmony_ci else 3194d4afb5ceSopenharmony_ci n = lws_ptr_diff(p, pstart) + (int)amount; 3195d4afb5ceSopenharmony_ci 3196d4afb5ceSopenharmony_ci lwsl_debug("%s: sending %d\n", __func__, n); 3197d4afb5ceSopenharmony_ci 3198d4afb5ceSopenharmony_ci if (n) { 3199d4afb5ceSopenharmony_ci lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 3200d4afb5ceSopenharmony_ci (int)context->timeout_secs); 3201d4afb5ceSopenharmony_ci 3202d4afb5ceSopenharmony_ci if (wsi->interpreting) { 3203d4afb5ceSopenharmony_ci args.p = (char *)p; 3204d4afb5ceSopenharmony_ci args.len = n; 3205d4afb5ceSopenharmony_ci args.max_len = (int)(unsigned int)poss + 128; 3206d4afb5ceSopenharmony_ci args.final = wsi->http.filepos + (unsigned int)n == 3207d4afb5ceSopenharmony_ci wsi->http.filelen; 3208d4afb5ceSopenharmony_ci args.chunked = wsi->sending_chunked; 3209d4afb5ceSopenharmony_ci if (user_callback_handle_rxflow( 3210d4afb5ceSopenharmony_ci wsi->a.vhost->protocols[ 3211d4afb5ceSopenharmony_ci (int)wsi->protocol_interpret_idx].callback, 3212d4afb5ceSopenharmony_ci wsi, LWS_CALLBACK_PROCESS_HTML, 3213d4afb5ceSopenharmony_ci wsi->user_space, &args, 0) < 0) 3214d4afb5ceSopenharmony_ci goto file_had_it; 3215d4afb5ceSopenharmony_ci n = args.len; 3216d4afb5ceSopenharmony_ci p = (unsigned char *)args.p; 3217d4afb5ceSopenharmony_ci } else 3218d4afb5ceSopenharmony_ci p = pstart; 3219d4afb5ceSopenharmony_ci 3220d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 3221d4afb5ceSopenharmony_ci if (wsi->http.range.send_ctr + 1 == 3222d4afb5ceSopenharmony_ci wsi->http.range.count_ranges && // last range 3223d4afb5ceSopenharmony_ci wsi->http.range.count_ranges > 1 && // was 2+ ranges (ie, multipart) 3224d4afb5ceSopenharmony_ci wsi->http.range.budget - amount == 0) {// final part 3225d4afb5ceSopenharmony_ci n += lws_snprintf((char *)pstart + n, 6, 3226d4afb5ceSopenharmony_ci "_lws\x0d\x0a"); // append trailing boundary 3227d4afb5ceSopenharmony_ci lwsl_debug("added trailing boundary\n"); 3228d4afb5ceSopenharmony_ci } 3229d4afb5ceSopenharmony_ci#endif 3230d4afb5ceSopenharmony_ci m = lws_write(wsi, p, (unsigned int)n, wsi->http.filepos + amount == 3231d4afb5ceSopenharmony_ci wsi->http.filelen ? 3232d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP); 3233d4afb5ceSopenharmony_ci if (m < 0) 3234d4afb5ceSopenharmony_ci goto file_had_it; 3235d4afb5ceSopenharmony_ci 3236d4afb5ceSopenharmony_ci wsi->http.filepos += amount; 3237d4afb5ceSopenharmony_ci 3238d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 3239d4afb5ceSopenharmony_ci if (wsi->http.range.count_ranges >= 1) { 3240d4afb5ceSopenharmony_ci wsi->http.range.budget -= amount; 3241d4afb5ceSopenharmony_ci if (wsi->http.range.budget == 0) { 3242d4afb5ceSopenharmony_ci lwsl_notice("range budget exhausted\n"); 3243d4afb5ceSopenharmony_ci wsi->http.range.inside = 0; 3244d4afb5ceSopenharmony_ci wsi->http.range.send_ctr++; 3245d4afb5ceSopenharmony_ci 3246d4afb5ceSopenharmony_ci if (lws_ranges_next(&wsi->http.range) < 1) { 3247d4afb5ceSopenharmony_ci finished = 1; 3248d4afb5ceSopenharmony_ci goto all_sent; 3249d4afb5ceSopenharmony_ci } 3250d4afb5ceSopenharmony_ci } 3251d4afb5ceSopenharmony_ci } 3252d4afb5ceSopenharmony_ci#endif 3253d4afb5ceSopenharmony_ci 3254d4afb5ceSopenharmony_ci if (m != n) { 3255d4afb5ceSopenharmony_ci /* adjust for what was not sent */ 3256d4afb5ceSopenharmony_ci if (lws_vfs_file_seek_cur(wsi->http.fop_fd, 3257d4afb5ceSopenharmony_ci m - n) == 3258d4afb5ceSopenharmony_ci (lws_fileofs_t)-1) 3259d4afb5ceSopenharmony_ci goto file_had_it; 3260d4afb5ceSopenharmony_ci } 3261d4afb5ceSopenharmony_ci } 3262d4afb5ceSopenharmony_ci 3263d4afb5ceSopenharmony_ciall_sent: 3264d4afb5ceSopenharmony_ci if ((!lws_has_buffered_out(wsi) 3265d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) 3266d4afb5ceSopenharmony_ci && !wsi->http.comp_ctx.buflist_comp && 3267d4afb5ceSopenharmony_ci !wsi->http.comp_ctx.may_have_more 3268d4afb5ceSopenharmony_ci#endif 3269d4afb5ceSopenharmony_ci ) && (wsi->http.filepos >= wsi->http.filelen 3270d4afb5ceSopenharmony_ci#if defined(LWS_WITH_RANGES) 3271d4afb5ceSopenharmony_ci || finished) 3272d4afb5ceSopenharmony_ci#else 3273d4afb5ceSopenharmony_ci ) 3274d4afb5ceSopenharmony_ci#endif 3275d4afb5ceSopenharmony_ci ) { 3276d4afb5ceSopenharmony_ci lwsi_set_state(wsi, LRS_ESTABLISHED); 3277d4afb5ceSopenharmony_ci /* we might be in keepalive, so close it off here */ 3278d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 3279d4afb5ceSopenharmony_ci 3280d4afb5ceSopenharmony_ci lwsl_debug("file completed\n"); 3281d4afb5ceSopenharmony_ci 3282d4afb5ceSopenharmony_ci if (wsi->a.protocol->callback && 3283d4afb5ceSopenharmony_ci user_callback_handle_rxflow(wsi->a.protocol->callback, 3284d4afb5ceSopenharmony_ci wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION, 3285d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0) < 0) { 3286d4afb5ceSopenharmony_ci /* 3287d4afb5ceSopenharmony_ci * For http/1.x, the choices from 3288d4afb5ceSopenharmony_ci * transaction_completed are either 3289d4afb5ceSopenharmony_ci * 0 to use the connection for pipelined 3290d4afb5ceSopenharmony_ci * or nonzero to hang it up. 3291d4afb5ceSopenharmony_ci * 3292d4afb5ceSopenharmony_ci * However for http/2. while we are 3293d4afb5ceSopenharmony_ci * still interested in hanging up the 3294d4afb5ceSopenharmony_ci * nwsi if there was a network-level 3295d4afb5ceSopenharmony_ci * fatal error, simply completing the 3296d4afb5ceSopenharmony_ci * transaction is a matter of the stream 3297d4afb5ceSopenharmony_ci * state, not the root connection at the 3298d4afb5ceSopenharmony_ci * network level 3299d4afb5ceSopenharmony_ci */ 3300d4afb5ceSopenharmony_ci if (wsi->mux_substream) 3301d4afb5ceSopenharmony_ci return 1; 3302d4afb5ceSopenharmony_ci else 3303d4afb5ceSopenharmony_ci return -1; 3304d4afb5ceSopenharmony_ci } 3305d4afb5ceSopenharmony_ci 3306d4afb5ceSopenharmony_ci return 1; /* >0 indicates completed */ 3307d4afb5ceSopenharmony_ci } 3308d4afb5ceSopenharmony_ci /* 3309d4afb5ceSopenharmony_ci * while(1) here causes us to spam the whole file contents into 3310d4afb5ceSopenharmony_ci * a hugely bloated output buffer if it ever can't send the 3311d4afb5ceSopenharmony_ci * whole chunk... 3312d4afb5ceSopenharmony_ci */ 3313d4afb5ceSopenharmony_ci } while (!lws_send_pipe_choked(wsi)); 3314d4afb5ceSopenharmony_ci 3315d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 3316d4afb5ceSopenharmony_ci 3317d4afb5ceSopenharmony_ci return 0; /* indicates further processing must be done */ 3318d4afb5ceSopenharmony_ci 3319d4afb5ceSopenharmony_cifile_had_it: 3320d4afb5ceSopenharmony_ci lws_vfs_file_close(&wsi->http.fop_fd); 3321d4afb5ceSopenharmony_ci 3322d4afb5ceSopenharmony_ci return -1; 3323d4afb5ceSopenharmony_ci} 3324d4afb5ceSopenharmony_ci 3325d4afb5ceSopenharmony_ci#endif 3326d4afb5ceSopenharmony_ci 3327d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 3328d4afb5ceSopenharmony_civoid 3329d4afb5ceSopenharmony_cilws_server_get_canonical_hostname(struct lws_context *context, 3330d4afb5ceSopenharmony_ci const struct lws_context_creation_info *info) 3331d4afb5ceSopenharmony_ci{ 3332d4afb5ceSopenharmony_ci if (lws_check_opt(info->options, 3333d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) 3334d4afb5ceSopenharmony_ci return; 3335d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) 3336d4afb5ceSopenharmony_ci /* find canonical hostname */ 3337d4afb5ceSopenharmony_ci if (gethostname((char *)context->canonical_hostname, 3338d4afb5ceSopenharmony_ci sizeof(context->canonical_hostname) - 1)) 3339d4afb5ceSopenharmony_ci lws_strncpy((char *)context->canonical_hostname, "unknown", 3340d4afb5ceSopenharmony_ci sizeof(context->canonical_hostname)); 3341d4afb5ceSopenharmony_ci 3342d4afb5ceSopenharmony_ci lwsl_cx_info(context, " canonical_hostname = %s\n", 3343d4afb5ceSopenharmony_ci context->canonical_hostname); 3344d4afb5ceSopenharmony_ci#else 3345d4afb5ceSopenharmony_ci (void)context; 3346d4afb5ceSopenharmony_ci#endif 3347d4afb5ceSopenharmony_ci} 3348d4afb5ceSopenharmony_ci#endif 3349d4afb5ceSopenharmony_ci 3350d4afb5ceSopenharmony_ciint 3351d4afb5ceSopenharmony_cilws_chunked_html_process(struct lws_process_html_args *args, 3352d4afb5ceSopenharmony_ci struct lws_process_html_state *s) 3353d4afb5ceSopenharmony_ci{ 3354d4afb5ceSopenharmony_ci char *sp, buffer[32]; 3355d4afb5ceSopenharmony_ci const char *pc; 3356d4afb5ceSopenharmony_ci int old_len, n; 3357d4afb5ceSopenharmony_ci 3358d4afb5ceSopenharmony_ci /* do replacements */ 3359d4afb5ceSopenharmony_ci sp = args->p; 3360d4afb5ceSopenharmony_ci old_len = args->len; 3361d4afb5ceSopenharmony_ci args->len = 0; 3362d4afb5ceSopenharmony_ci s->start = sp; 3363d4afb5ceSopenharmony_ci while (sp < args->p + old_len) { 3364d4afb5ceSopenharmony_ci 3365d4afb5ceSopenharmony_ci if (args->len + 7 >= args->max_len) { 3366d4afb5ceSopenharmony_ci lwsl_err("Used up interpret padding\n"); 3367d4afb5ceSopenharmony_ci return -1; 3368d4afb5ceSopenharmony_ci } 3369d4afb5ceSopenharmony_ci 3370d4afb5ceSopenharmony_ci if ((!s->pos && *sp == '$') || s->pos) { 3371d4afb5ceSopenharmony_ci int hits = 0, hit = 0; 3372d4afb5ceSopenharmony_ci 3373d4afb5ceSopenharmony_ci if (!s->pos) 3374d4afb5ceSopenharmony_ci s->start = sp; 3375d4afb5ceSopenharmony_ci s->swallow[s->pos++] = *sp; 3376d4afb5ceSopenharmony_ci if (s->pos == sizeof(s->swallow) - 1) 3377d4afb5ceSopenharmony_ci goto skip; 3378d4afb5ceSopenharmony_ci for (n = 0; n < s->count_vars; n++) 3379d4afb5ceSopenharmony_ci if (!strncmp(s->swallow, s->vars[n], (unsigned int)s->pos)) { 3380d4afb5ceSopenharmony_ci hits++; 3381d4afb5ceSopenharmony_ci hit = n; 3382d4afb5ceSopenharmony_ci } 3383d4afb5ceSopenharmony_ci if (!hits) { 3384d4afb5ceSopenharmony_ciskip: 3385d4afb5ceSopenharmony_ci s->swallow[s->pos] = '\0'; 3386d4afb5ceSopenharmony_ci memcpy(s->start, s->swallow, (unsigned int)s->pos); 3387d4afb5ceSopenharmony_ci args->len++; 3388d4afb5ceSopenharmony_ci s->pos = 0; 3389d4afb5ceSopenharmony_ci sp = s->start + 1; 3390d4afb5ceSopenharmony_ci continue; 3391d4afb5ceSopenharmony_ci } 3392d4afb5ceSopenharmony_ci if (hits == 1 && s->pos == (int)strlen(s->vars[hit])) { 3393d4afb5ceSopenharmony_ci pc = s->replace(s->data, hit); 3394d4afb5ceSopenharmony_ci if (!pc) 3395d4afb5ceSopenharmony_ci pc = "NULL"; 3396d4afb5ceSopenharmony_ci n = (int)strlen(pc); 3397d4afb5ceSopenharmony_ci s->swallow[s->pos] = '\0'; 3398d4afb5ceSopenharmony_ci if (n != s->pos) { 3399d4afb5ceSopenharmony_ci memmove(s->start + n, s->start + s->pos, 3400d4afb5ceSopenharmony_ci (unsigned int)(old_len - (sp - args->p) - 1)); 3401d4afb5ceSopenharmony_ci old_len += (n - s->pos) + 1; 3402d4afb5ceSopenharmony_ci } 3403d4afb5ceSopenharmony_ci memcpy(s->start, pc, (unsigned int)n); 3404d4afb5ceSopenharmony_ci args->len++; 3405d4afb5ceSopenharmony_ci sp = s->start + 1; 3406d4afb5ceSopenharmony_ci 3407d4afb5ceSopenharmony_ci s->pos = 0; 3408d4afb5ceSopenharmony_ci } 3409d4afb5ceSopenharmony_ci sp++; 3410d4afb5ceSopenharmony_ci continue; 3411d4afb5ceSopenharmony_ci } 3412d4afb5ceSopenharmony_ci 3413d4afb5ceSopenharmony_ci args->len++; 3414d4afb5ceSopenharmony_ci sp++; 3415d4afb5ceSopenharmony_ci } 3416d4afb5ceSopenharmony_ci 3417d4afb5ceSopenharmony_ci if (args->chunked) { 3418d4afb5ceSopenharmony_ci /* no space left for final chunk trailer */ 3419d4afb5ceSopenharmony_ci if (args->final && args->len + 7 >= args->max_len) 3420d4afb5ceSopenharmony_ci return -1; 3421d4afb5ceSopenharmony_ci 3422d4afb5ceSopenharmony_ci n = sprintf(buffer, "%X\x0d\x0a", args->len); 3423d4afb5ceSopenharmony_ci 3424d4afb5ceSopenharmony_ci args->p -= n; 3425d4afb5ceSopenharmony_ci memcpy(args->p, buffer, (unsigned int)n); 3426d4afb5ceSopenharmony_ci args->len += n; 3427d4afb5ceSopenharmony_ci 3428d4afb5ceSopenharmony_ci if (args->final) { 3429d4afb5ceSopenharmony_ci sp = args->p + args->len; 3430d4afb5ceSopenharmony_ci *sp++ = '\x0d'; 3431d4afb5ceSopenharmony_ci *sp++ = '\x0a'; 3432d4afb5ceSopenharmony_ci *sp++ = '0'; 3433d4afb5ceSopenharmony_ci *sp++ = '\x0d'; 3434d4afb5ceSopenharmony_ci *sp++ = '\x0a'; 3435d4afb5ceSopenharmony_ci *sp++ = '\x0d'; 3436d4afb5ceSopenharmony_ci *sp++ = '\x0a'; 3437d4afb5ceSopenharmony_ci args->len += 7; 3438d4afb5ceSopenharmony_ci } else { 3439d4afb5ceSopenharmony_ci sp = args->p + args->len; 3440d4afb5ceSopenharmony_ci *sp++ = '\x0d'; 3441d4afb5ceSopenharmony_ci *sp++ = '\x0a'; 3442d4afb5ceSopenharmony_ci args->len += 2; 3443d4afb5ceSopenharmony_ci } 3444d4afb5ceSopenharmony_ci } 3445d4afb5ceSopenharmony_ci 3446d4afb5ceSopenharmony_ci return 0; 3447d4afb5ceSopenharmony_ci} 3448