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_cistatic const unsigned char lextable_h1[] = { 28d4afb5ceSopenharmony_ci #include "lextable.h" 29d4afb5ceSopenharmony_ci}; 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci#define FAIL_CHAR 0x08 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_ci#define UHO_NLEN 0 36d4afb5ceSopenharmony_ci#define UHO_VLEN 2 37d4afb5ceSopenharmony_ci#define UHO_LL 4 38d4afb5ceSopenharmony_ci#define UHO_NAME 8 39d4afb5ceSopenharmony_ci 40d4afb5ceSopenharmony_ci#endif 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_cistatic struct allocated_headers * 43d4afb5ceSopenharmony_ci_lws_create_ah(struct lws_context_per_thread *pt, ah_data_idx_t data_size) 44d4afb5ceSopenharmony_ci{ 45d4afb5ceSopenharmony_ci struct allocated_headers *ah = lws_zalloc(sizeof(*ah), "ah struct"); 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_ci if (!ah) 48d4afb5ceSopenharmony_ci return NULL; 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_ci ah->data = lws_malloc(data_size, "ah data"); 51d4afb5ceSopenharmony_ci if (!ah->data) { 52d4afb5ceSopenharmony_ci lws_free(ah); 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_ci return NULL; 55d4afb5ceSopenharmony_ci } 56d4afb5ceSopenharmony_ci ah->next = pt->http.ah_list; 57d4afb5ceSopenharmony_ci pt->http.ah_list = ah; 58d4afb5ceSopenharmony_ci ah->data_length = data_size; 59d4afb5ceSopenharmony_ci pt->http.ah_pool_length++; 60d4afb5ceSopenharmony_ci 61d4afb5ceSopenharmony_ci lwsl_info("%s: created ah %p (size %d): pool length %u\n", __func__, 62d4afb5ceSopenharmony_ci ah, (int)data_size, (unsigned int)pt->http.ah_pool_length); 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_ci return ah; 65d4afb5ceSopenharmony_ci} 66d4afb5ceSopenharmony_ci 67d4afb5ceSopenharmony_ciint 68d4afb5ceSopenharmony_ci_lws_destroy_ah(struct lws_context_per_thread *pt, struct allocated_headers *ah) 69d4afb5ceSopenharmony_ci{ 70d4afb5ceSopenharmony_ci lws_start_foreach_llp(struct allocated_headers **, a, pt->http.ah_list) { 71d4afb5ceSopenharmony_ci if ((*a) == ah) { 72d4afb5ceSopenharmony_ci *a = ah->next; 73d4afb5ceSopenharmony_ci pt->http.ah_pool_length--; 74d4afb5ceSopenharmony_ci lwsl_info("%s: freed ah %p : pool length %u\n", 75d4afb5ceSopenharmony_ci __func__, ah, 76d4afb5ceSopenharmony_ci (unsigned int)pt->http.ah_pool_length); 77d4afb5ceSopenharmony_ci if (ah->data) 78d4afb5ceSopenharmony_ci lws_free(ah->data); 79d4afb5ceSopenharmony_ci lws_free(ah); 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci return 0; 82d4afb5ceSopenharmony_ci } 83d4afb5ceSopenharmony_ci } lws_end_foreach_llp(a, next); 84d4afb5ceSopenharmony_ci 85d4afb5ceSopenharmony_ci return 1; 86d4afb5ceSopenharmony_ci} 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_civoid 89d4afb5ceSopenharmony_ci_lws_header_table_reset(struct allocated_headers *ah) 90d4afb5ceSopenharmony_ci{ 91d4afb5ceSopenharmony_ci /* init the ah to reflect no headers or data have appeared yet */ 92d4afb5ceSopenharmony_ci memset(ah->frag_index, 0, sizeof(ah->frag_index)); 93d4afb5ceSopenharmony_ci memset(ah->frags, 0, sizeof(ah->frags)); 94d4afb5ceSopenharmony_ci ah->nfrag = 0; 95d4afb5ceSopenharmony_ci ah->pos = 0; 96d4afb5ceSopenharmony_ci ah->http_response = 0; 97d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_NAME_PART; 98d4afb5ceSopenharmony_ci ah->lextable_pos = 0; 99d4afb5ceSopenharmony_ci ah->unk_pos = 0; 100d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 101d4afb5ceSopenharmony_ci ah->unk_ll_head = 0; 102d4afb5ceSopenharmony_ci ah->unk_ll_tail = 0; 103d4afb5ceSopenharmony_ci#endif 104d4afb5ceSopenharmony_ci} 105d4afb5ceSopenharmony_ci 106d4afb5ceSopenharmony_ci// doesn't scrub the ah rxbuffer by default, parent must do if needed 107d4afb5ceSopenharmony_ci 108d4afb5ceSopenharmony_civoid 109d4afb5ceSopenharmony_ci__lws_header_table_reset(struct lws *wsi, int autoservice) 110d4afb5ceSopenharmony_ci{ 111d4afb5ceSopenharmony_ci struct allocated_headers *ah = wsi->http.ah; 112d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 113d4afb5ceSopenharmony_ci struct lws_pollfd *pfd; 114d4afb5ceSopenharmony_ci 115d4afb5ceSopenharmony_ci /* if we have the idea we're resetting 'our' ah, must be bound to one */ 116d4afb5ceSopenharmony_ci assert(ah); 117d4afb5ceSopenharmony_ci /* ah also concurs with ownership */ 118d4afb5ceSopenharmony_ci assert(ah->wsi == wsi); 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci _lws_header_table_reset(ah); 121d4afb5ceSopenharmony_ci 122d4afb5ceSopenharmony_ci /* since we will restart the ah, our new headers are not completed */ 123d4afb5ceSopenharmony_ci wsi->hdr_parsing_completed = 0; 124d4afb5ceSopenharmony_ci 125d4afb5ceSopenharmony_ci /* while we hold the ah, keep a timeout on the wsi */ 126d4afb5ceSopenharmony_ci __lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH, 127d4afb5ceSopenharmony_ci wsi->a.vhost->timeout_secs_ah_idle); 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_ci time(&ah->assigned); 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci if (wsi->position_in_fds_table != LWS_NO_FDS_POS && 132d4afb5ceSopenharmony_ci lws_buflist_next_segment_len(&wsi->buflist, NULL) && 133d4afb5ceSopenharmony_ci autoservice) { 134d4afb5ceSopenharmony_ci lwsl_debug("%s: service on readbuf ah\n", __func__); 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci pt = &wsi->a.context->pt[(int)wsi->tsi]; 137d4afb5ceSopenharmony_ci /* 138d4afb5ceSopenharmony_ci * Unlike a normal connect, we have the headers already 139d4afb5ceSopenharmony_ci * (or the first part of them anyway) 140d4afb5ceSopenharmony_ci */ 141d4afb5ceSopenharmony_ci pfd = &pt->fds[wsi->position_in_fds_table]; 142d4afb5ceSopenharmony_ci pfd->revents |= LWS_POLLIN; 143d4afb5ceSopenharmony_ci lwsl_err("%s: calling service\n", __func__); 144d4afb5ceSopenharmony_ci lws_service_fd_tsi(wsi->a.context, pfd, wsi->tsi); 145d4afb5ceSopenharmony_ci } 146d4afb5ceSopenharmony_ci} 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_civoid 149d4afb5ceSopenharmony_cilws_header_table_reset(struct lws *wsi, int autoservice) 150d4afb5ceSopenharmony_ci{ 151d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 152d4afb5ceSopenharmony_ci 153d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci __lws_header_table_reset(wsi, autoservice); 156d4afb5ceSopenharmony_ci 157d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 158d4afb5ceSopenharmony_ci} 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_cistatic void 161d4afb5ceSopenharmony_ci_lws_header_ensure_we_are_on_waiting_list(struct lws *wsi) 162d4afb5ceSopenharmony_ci{ 163d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 164d4afb5ceSopenharmony_ci struct lws_pollargs pa; 165d4afb5ceSopenharmony_ci struct lws **pwsi = &pt->http.ah_wait_list; 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci while (*pwsi) { 168d4afb5ceSopenharmony_ci if (*pwsi == wsi) 169d4afb5ceSopenharmony_ci return; 170d4afb5ceSopenharmony_ci pwsi = &(*pwsi)->http.ah_wait_list; 171d4afb5ceSopenharmony_ci } 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci lwsl_info("%s: wsi: %s\n", __func__, lws_wsi_tag(wsi)); 174d4afb5ceSopenharmony_ci wsi->http.ah_wait_list = pt->http.ah_wait_list; 175d4afb5ceSopenharmony_ci pt->http.ah_wait_list = wsi; 176d4afb5ceSopenharmony_ci pt->http.ah_wait_list_length++; 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci /* we cannot accept input then */ 179d4afb5ceSopenharmony_ci 180d4afb5ceSopenharmony_ci _lws_change_pollfd(wsi, LWS_POLLIN, 0, &pa); 181d4afb5ceSopenharmony_ci} 182d4afb5ceSopenharmony_ci 183d4afb5ceSopenharmony_cistatic int 184d4afb5ceSopenharmony_ci__lws_remove_from_ah_waiting_list(struct lws *wsi) 185d4afb5ceSopenharmony_ci{ 186d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 187d4afb5ceSopenharmony_ci struct lws **pwsi =&pt->http.ah_wait_list; 188d4afb5ceSopenharmony_ci 189d4afb5ceSopenharmony_ci while (*pwsi) { 190d4afb5ceSopenharmony_ci if (*pwsi == wsi) { 191d4afb5ceSopenharmony_ci lwsl_info("%s: wsi %s\n", __func__, lws_wsi_tag(wsi)); 192d4afb5ceSopenharmony_ci /* point prev guy to our next */ 193d4afb5ceSopenharmony_ci *pwsi = wsi->http.ah_wait_list; 194d4afb5ceSopenharmony_ci /* we shouldn't point anywhere now */ 195d4afb5ceSopenharmony_ci wsi->http.ah_wait_list = NULL; 196d4afb5ceSopenharmony_ci pt->http.ah_wait_list_length--; 197d4afb5ceSopenharmony_ci 198d4afb5ceSopenharmony_ci return 1; 199d4afb5ceSopenharmony_ci } 200d4afb5ceSopenharmony_ci pwsi = &(*pwsi)->http.ah_wait_list; 201d4afb5ceSopenharmony_ci } 202d4afb5ceSopenharmony_ci 203d4afb5ceSopenharmony_ci return 0; 204d4afb5ceSopenharmony_ci} 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ciint LWS_WARN_UNUSED_RESULT 207d4afb5ceSopenharmony_cilws_header_table_attach(struct lws *wsi, int autoservice) 208d4afb5ceSopenharmony_ci{ 209d4afb5ceSopenharmony_ci struct lws_context *context = wsi->a.context; 210d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 211d4afb5ceSopenharmony_ci struct lws_pollargs pa; 212d4afb5ceSopenharmony_ci int n; 213d4afb5ceSopenharmony_ci 214d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT) 215d4afb5ceSopenharmony_ci if (lwsi_role_mqtt(wsi)) 216d4afb5ceSopenharmony_ci goto connect_via_info2; 217d4afb5ceSopenharmony_ci#endif 218d4afb5ceSopenharmony_ci 219d4afb5ceSopenharmony_ci lwsl_info("%s: %s: ah %p (tsi %d, count = %d) in\n", __func__, 220d4afb5ceSopenharmony_ci lws_wsi_tag(wsi), (void *)wsi->http.ah, wsi->tsi, 221d4afb5ceSopenharmony_ci pt->http.ah_count_in_use); 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci if (!lwsi_role_http(wsi)) { 224d4afb5ceSopenharmony_ci lwsl_err("%s: bad role %s\n", __func__, wsi->role_ops->name); 225d4afb5ceSopenharmony_ci assert(0); 226d4afb5ceSopenharmony_ci return -1; 227d4afb5ceSopenharmony_ci } 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci /* if we are already bound to one, just clear it down */ 232d4afb5ceSopenharmony_ci if (wsi->http.ah) { 233d4afb5ceSopenharmony_ci lwsl_info("%s: cleardown\n", __func__); 234d4afb5ceSopenharmony_ci goto reset; 235d4afb5ceSopenharmony_ci } 236d4afb5ceSopenharmony_ci 237d4afb5ceSopenharmony_ci n = pt->http.ah_count_in_use == (int)context->max_http_header_pool; 238d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) 239d4afb5ceSopenharmony_ci if (!n) 240d4afb5ceSopenharmony_ci n = lws_peer_confirm_ah_attach_ok(context, wsi->peer); 241d4afb5ceSopenharmony_ci#endif 242d4afb5ceSopenharmony_ci if (n) { 243d4afb5ceSopenharmony_ci /* 244d4afb5ceSopenharmony_ci * Pool is either all busy, or we don't want to give this 245d4afb5ceSopenharmony_ci * particular guy an ah right now... 246d4afb5ceSopenharmony_ci * 247d4afb5ceSopenharmony_ci * Make sure we are on the waiting list, and return that we 248d4afb5ceSopenharmony_ci * weren't able to provide the ah 249d4afb5ceSopenharmony_ci */ 250d4afb5ceSopenharmony_ci _lws_header_ensure_we_are_on_waiting_list(wsi); 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci goto bail; 253d4afb5ceSopenharmony_ci } 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci __lws_remove_from_ah_waiting_list(wsi); 256d4afb5ceSopenharmony_ci 257d4afb5ceSopenharmony_ci wsi->http.ah = _lws_create_ah(pt, context->max_http_header_data); 258d4afb5ceSopenharmony_ci if (!wsi->http.ah) { /* we could not create an ah */ 259d4afb5ceSopenharmony_ci _lws_header_ensure_we_are_on_waiting_list(wsi); 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci goto bail; 262d4afb5ceSopenharmony_ci } 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci wsi->http.ah->in_use = 1; 265d4afb5ceSopenharmony_ci wsi->http.ah->wsi = wsi; /* mark our owner */ 266d4afb5ceSopenharmony_ci pt->http.ah_count_in_use++; 267d4afb5ceSopenharmony_ci 268d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) && (defined(LWS_ROLE_H1) || \ 269d4afb5ceSopenharmony_ci defined(LWS_ROLE_H2)) 270d4afb5ceSopenharmony_ci lws_context_lock(context, "ah attach"); /* <========================= */ 271d4afb5ceSopenharmony_ci if (wsi->peer) 272d4afb5ceSopenharmony_ci wsi->peer->http.count_ah++; 273d4afb5ceSopenharmony_ci lws_context_unlock(context); /* ====================================> */ 274d4afb5ceSopenharmony_ci#endif 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_ci _lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa); 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ci lwsl_info("%s: did attach wsi %s: ah %p: count %d (on exit)\n", __func__, 279d4afb5ceSopenharmony_ci lws_wsi_tag(wsi), (void *)wsi->http.ah, pt->http.ah_count_in_use); 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_cireset: 282d4afb5ceSopenharmony_ci __lws_header_table_reset(wsi, autoservice); 283d4afb5ceSopenharmony_ci 284d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 285d4afb5ceSopenharmony_ci 286d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 287d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_MQTT) 288d4afb5ceSopenharmony_ciconnect_via_info2: 289d4afb5ceSopenharmony_ci#endif 290d4afb5ceSopenharmony_ci if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED) 291d4afb5ceSopenharmony_ci if (!lws_http_client_connect_via_info2(wsi)) 292d4afb5ceSopenharmony_ci /* our client connect has failed, the wsi 293d4afb5ceSopenharmony_ci * has been closed 294d4afb5ceSopenharmony_ci */ 295d4afb5ceSopenharmony_ci return -1; 296d4afb5ceSopenharmony_ci#endif 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_ci return 0; 299d4afb5ceSopenharmony_ci 300d4afb5ceSopenharmony_cibail: 301d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 302d4afb5ceSopenharmony_ci 303d4afb5ceSopenharmony_ci return 1; 304d4afb5ceSopenharmony_ci} 305d4afb5ceSopenharmony_ci 306d4afb5ceSopenharmony_ciint __lws_header_table_detach(struct lws *wsi, int autoservice) 307d4afb5ceSopenharmony_ci{ 308d4afb5ceSopenharmony_ci struct lws_context *context = wsi->a.context; 309d4afb5ceSopenharmony_ci struct allocated_headers *ah = wsi->http.ah; 310d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 311d4afb5ceSopenharmony_ci struct lws_pollargs pa; 312d4afb5ceSopenharmony_ci struct lws **pwsi, **pwsi_eligible; 313d4afb5ceSopenharmony_ci time_t now; 314d4afb5ceSopenharmony_ci 315d4afb5ceSopenharmony_ci __lws_remove_from_ah_waiting_list(wsi); 316d4afb5ceSopenharmony_ci 317d4afb5ceSopenharmony_ci if (!ah) 318d4afb5ceSopenharmony_ci return 0; 319d4afb5ceSopenharmony_ci 320d4afb5ceSopenharmony_ci lwsl_info("%s: %s: ah %p (tsi=%d, count = %d)\n", __func__, 321d4afb5ceSopenharmony_ci lws_wsi_tag(wsi), (void *)ah, wsi->tsi, 322d4afb5ceSopenharmony_ci pt->http.ah_count_in_use); 323d4afb5ceSopenharmony_ci 324d4afb5ceSopenharmony_ci /* we did have an ah attached */ 325d4afb5ceSopenharmony_ci time(&now); 326d4afb5ceSopenharmony_ci if (ah->assigned && now - ah->assigned > 3) { 327d4afb5ceSopenharmony_ci /* 328d4afb5ceSopenharmony_ci * we're detaching the ah, but it was held an 329d4afb5ceSopenharmony_ci * unreasonably long time 330d4afb5ceSopenharmony_ci */ 331d4afb5ceSopenharmony_ci lwsl_debug("%s: %s: ah held %ds, role/state 0x%lx 0x%x," 332d4afb5ceSopenharmony_ci "\n", __func__, lws_wsi_tag(wsi), 333d4afb5ceSopenharmony_ci (int)(now - ah->assigned), 334d4afb5ceSopenharmony_ci (unsigned long)lwsi_role(wsi), lwsi_state(wsi)); 335d4afb5ceSopenharmony_ci } 336d4afb5ceSopenharmony_ci 337d4afb5ceSopenharmony_ci ah->assigned = 0; 338d4afb5ceSopenharmony_ci 339d4afb5ceSopenharmony_ci /* if we think we're detaching one, there should be one in use */ 340d4afb5ceSopenharmony_ci assert(pt->http.ah_count_in_use > 0); 341d4afb5ceSopenharmony_ci /* and this specific one should have been in use */ 342d4afb5ceSopenharmony_ci assert(ah->in_use); 343d4afb5ceSopenharmony_ci memset(&wsi->http.ah, 0, sizeof(wsi->http.ah)); 344d4afb5ceSopenharmony_ci 345d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) 346d4afb5ceSopenharmony_ci if (ah->wsi) 347d4afb5ceSopenharmony_ci lws_peer_track_ah_detach(context, wsi->peer); 348d4afb5ceSopenharmony_ci#endif 349d4afb5ceSopenharmony_ci ah->wsi = NULL; /* no owner */ 350d4afb5ceSopenharmony_ci wsi->http.ah = NULL; 351d4afb5ceSopenharmony_ci 352d4afb5ceSopenharmony_ci pwsi = &pt->http.ah_wait_list; 353d4afb5ceSopenharmony_ci 354d4afb5ceSopenharmony_ci /* oh there is nobody on the waiting list... leave the ah unattached */ 355d4afb5ceSopenharmony_ci if (!*pwsi) 356d4afb5ceSopenharmony_ci goto nobody_usable_waiting; 357d4afb5ceSopenharmony_ci 358d4afb5ceSopenharmony_ci /* 359d4afb5ceSopenharmony_ci * at least one wsi on the same tsi is waiting, give it to oldest guy 360d4afb5ceSopenharmony_ci * who is allowed to take it (if any) 361d4afb5ceSopenharmony_ci */ 362d4afb5ceSopenharmony_ci lwsl_info("%s: pt wait list %s\n", __func__, lws_wsi_tag(*pwsi)); 363d4afb5ceSopenharmony_ci wsi = NULL; 364d4afb5ceSopenharmony_ci pwsi_eligible = NULL; 365d4afb5ceSopenharmony_ci 366d4afb5ceSopenharmony_ci while (*pwsi) { 367d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) 368d4afb5ceSopenharmony_ci /* are we willing to give this guy an ah? */ 369d4afb5ceSopenharmony_ci if (!lws_peer_confirm_ah_attach_ok(context, (*pwsi)->peer)) 370d4afb5ceSopenharmony_ci#endif 371d4afb5ceSopenharmony_ci { 372d4afb5ceSopenharmony_ci wsi = *pwsi; 373d4afb5ceSopenharmony_ci pwsi_eligible = pwsi; 374d4afb5ceSopenharmony_ci } 375d4afb5ceSopenharmony_ci 376d4afb5ceSopenharmony_ci pwsi = &(*pwsi)->http.ah_wait_list; 377d4afb5ceSopenharmony_ci } 378d4afb5ceSopenharmony_ci 379d4afb5ceSopenharmony_ci if (!wsi) /* everybody waiting already has too many ah... */ 380d4afb5ceSopenharmony_ci goto nobody_usable_waiting; 381d4afb5ceSopenharmony_ci 382d4afb5ceSopenharmony_ci lwsl_info("%s: transferring ah to last eligible wsi in wait list " 383d4afb5ceSopenharmony_ci "%s (wsistate 0x%lx)\n", __func__, lws_wsi_tag(wsi), 384d4afb5ceSopenharmony_ci (unsigned long)wsi->wsistate); 385d4afb5ceSopenharmony_ci 386d4afb5ceSopenharmony_ci wsi->http.ah = ah; 387d4afb5ceSopenharmony_ci ah->wsi = wsi; /* new owner */ 388d4afb5ceSopenharmony_ci 389d4afb5ceSopenharmony_ci __lws_header_table_reset(wsi, autoservice); 390d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) && (defined(LWS_ROLE_H1) || \ 391d4afb5ceSopenharmony_ci defined(LWS_ROLE_H2)) 392d4afb5ceSopenharmony_ci lws_context_lock(context, "ah detach"); /* <========================= */ 393d4afb5ceSopenharmony_ci if (wsi->peer) 394d4afb5ceSopenharmony_ci wsi->peer->http.count_ah++; 395d4afb5ceSopenharmony_ci lws_context_unlock(context); /* ====================================> */ 396d4afb5ceSopenharmony_ci#endif 397d4afb5ceSopenharmony_ci 398d4afb5ceSopenharmony_ci /* clients acquire the ah and then insert themselves in fds table... */ 399d4afb5ceSopenharmony_ci if (wsi->position_in_fds_table != LWS_NO_FDS_POS) { 400d4afb5ceSopenharmony_ci lwsl_info("%s: Enabling %s POLLIN\n", __func__, lws_wsi_tag(wsi)); 401d4afb5ceSopenharmony_ci 402d4afb5ceSopenharmony_ci /* he has been stuck waiting for an ah, but now his wait is 403d4afb5ceSopenharmony_ci * over, let him progress */ 404d4afb5ceSopenharmony_ci 405d4afb5ceSopenharmony_ci _lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa); 406d4afb5ceSopenharmony_ci } 407d4afb5ceSopenharmony_ci 408d4afb5ceSopenharmony_ci /* point prev guy to next guy in list instead */ 409d4afb5ceSopenharmony_ci *pwsi_eligible = wsi->http.ah_wait_list; 410d4afb5ceSopenharmony_ci /* the guy who got one is out of the list */ 411d4afb5ceSopenharmony_ci wsi->http.ah_wait_list = NULL; 412d4afb5ceSopenharmony_ci pt->http.ah_wait_list_length--; 413d4afb5ceSopenharmony_ci 414d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 415d4afb5ceSopenharmony_ci if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED) { 416d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 417d4afb5ceSopenharmony_ci 418d4afb5ceSopenharmony_ci if (!lws_http_client_connect_via_info2(wsi)) { 419d4afb5ceSopenharmony_ci /* our client connect has failed, the wsi 420d4afb5ceSopenharmony_ci * has been closed 421d4afb5ceSopenharmony_ci */ 422d4afb5ceSopenharmony_ci 423d4afb5ceSopenharmony_ci return -1; 424d4afb5ceSopenharmony_ci } 425d4afb5ceSopenharmony_ci return 0; 426d4afb5ceSopenharmony_ci } 427d4afb5ceSopenharmony_ci#endif 428d4afb5ceSopenharmony_ci 429d4afb5ceSopenharmony_ci assert(!!pt->http.ah_wait_list_length == 430d4afb5ceSopenharmony_ci !!(lws_intptr_t)pt->http.ah_wait_list); 431d4afb5ceSopenharmony_cibail: 432d4afb5ceSopenharmony_ci lwsl_info("%s: %s: ah %p (tsi=%d, count = %d)\n", __func__, 433d4afb5ceSopenharmony_ci lws_wsi_tag(wsi), (void *)ah, pt->tid, pt->http.ah_count_in_use); 434d4afb5ceSopenharmony_ci 435d4afb5ceSopenharmony_ci return 0; 436d4afb5ceSopenharmony_ci 437d4afb5ceSopenharmony_cinobody_usable_waiting: 438d4afb5ceSopenharmony_ci lwsl_info("%s: nobody usable waiting\n", __func__); 439d4afb5ceSopenharmony_ci _lws_destroy_ah(pt, ah); 440d4afb5ceSopenharmony_ci pt->http.ah_count_in_use--; 441d4afb5ceSopenharmony_ci 442d4afb5ceSopenharmony_ci goto bail; 443d4afb5ceSopenharmony_ci} 444d4afb5ceSopenharmony_ci 445d4afb5ceSopenharmony_ciint lws_header_table_detach(struct lws *wsi, int autoservice) 446d4afb5ceSopenharmony_ci{ 447d4afb5ceSopenharmony_ci struct lws_context *context = wsi->a.context; 448d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 449d4afb5ceSopenharmony_ci int n; 450d4afb5ceSopenharmony_ci 451d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 452d4afb5ceSopenharmony_ci n = __lws_header_table_detach(wsi, autoservice); 453d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 454d4afb5ceSopenharmony_ci 455d4afb5ceSopenharmony_ci return n; 456d4afb5ceSopenharmony_ci} 457d4afb5ceSopenharmony_ci 458d4afb5ceSopenharmony_ciint 459d4afb5ceSopenharmony_cilws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx) 460d4afb5ceSopenharmony_ci{ 461d4afb5ceSopenharmony_ci int n; 462d4afb5ceSopenharmony_ci 463d4afb5ceSopenharmony_ci if (!wsi->http.ah) 464d4afb5ceSopenharmony_ci return 0; 465d4afb5ceSopenharmony_ci 466d4afb5ceSopenharmony_ci n = wsi->http.ah->frag_index[h]; 467d4afb5ceSopenharmony_ci if (!n) 468d4afb5ceSopenharmony_ci return 0; 469d4afb5ceSopenharmony_ci do { 470d4afb5ceSopenharmony_ci if (!frag_idx) 471d4afb5ceSopenharmony_ci return wsi->http.ah->frags[n].len; 472d4afb5ceSopenharmony_ci n = wsi->http.ah->frags[n].nfrag; 473d4afb5ceSopenharmony_ci } while (frag_idx-- && n); 474d4afb5ceSopenharmony_ci 475d4afb5ceSopenharmony_ci return 0; 476d4afb5ceSopenharmony_ci} 477d4afb5ceSopenharmony_ci 478d4afb5ceSopenharmony_ciint lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h) 479d4afb5ceSopenharmony_ci{ 480d4afb5ceSopenharmony_ci int n; 481d4afb5ceSopenharmony_ci int len = 0; 482d4afb5ceSopenharmony_ci 483d4afb5ceSopenharmony_ci if (!wsi->http.ah) 484d4afb5ceSopenharmony_ci return 0; 485d4afb5ceSopenharmony_ci 486d4afb5ceSopenharmony_ci n = wsi->http.ah->frag_index[h]; 487d4afb5ceSopenharmony_ci if (!n) 488d4afb5ceSopenharmony_ci return 0; 489d4afb5ceSopenharmony_ci do { 490d4afb5ceSopenharmony_ci len += wsi->http.ah->frags[n].len; 491d4afb5ceSopenharmony_ci n = wsi->http.ah->frags[n].nfrag; 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci if (n) 494d4afb5ceSopenharmony_ci len++; 495d4afb5ceSopenharmony_ci 496d4afb5ceSopenharmony_ci } while (n); 497d4afb5ceSopenharmony_ci 498d4afb5ceSopenharmony_ci return len; 499d4afb5ceSopenharmony_ci} 500d4afb5ceSopenharmony_ci 501d4afb5ceSopenharmony_ciint lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len, 502d4afb5ceSopenharmony_ci enum lws_token_indexes h, int frag_idx) 503d4afb5ceSopenharmony_ci{ 504d4afb5ceSopenharmony_ci int n = 0; 505d4afb5ceSopenharmony_ci int f; 506d4afb5ceSopenharmony_ci 507d4afb5ceSopenharmony_ci if (!wsi->http.ah) 508d4afb5ceSopenharmony_ci return -1; 509d4afb5ceSopenharmony_ci 510d4afb5ceSopenharmony_ci f = wsi->http.ah->frag_index[h]; 511d4afb5ceSopenharmony_ci 512d4afb5ceSopenharmony_ci if (!f) 513d4afb5ceSopenharmony_ci return -1; 514d4afb5ceSopenharmony_ci 515d4afb5ceSopenharmony_ci while (n < frag_idx) { 516d4afb5ceSopenharmony_ci f = wsi->http.ah->frags[f].nfrag; 517d4afb5ceSopenharmony_ci if (!f) 518d4afb5ceSopenharmony_ci return -1; 519d4afb5ceSopenharmony_ci n++; 520d4afb5ceSopenharmony_ci } 521d4afb5ceSopenharmony_ci 522d4afb5ceSopenharmony_ci if (wsi->http.ah->frags[f].len >= len) 523d4afb5ceSopenharmony_ci return -1; 524d4afb5ceSopenharmony_ci 525d4afb5ceSopenharmony_ci memcpy(dst, wsi->http.ah->data + wsi->http.ah->frags[f].offset, 526d4afb5ceSopenharmony_ci wsi->http.ah->frags[f].len); 527d4afb5ceSopenharmony_ci dst[wsi->http.ah->frags[f].len] = '\0'; 528d4afb5ceSopenharmony_ci 529d4afb5ceSopenharmony_ci return wsi->http.ah->frags[f].len; 530d4afb5ceSopenharmony_ci} 531d4afb5ceSopenharmony_ci 532d4afb5ceSopenharmony_ciint lws_hdr_copy(struct lws *wsi, char *dst, int len, 533d4afb5ceSopenharmony_ci enum lws_token_indexes h) 534d4afb5ceSopenharmony_ci{ 535d4afb5ceSopenharmony_ci int toklen = lws_hdr_total_length(wsi, h), n, comma; 536d4afb5ceSopenharmony_ci 537d4afb5ceSopenharmony_ci *dst = '\0'; 538d4afb5ceSopenharmony_ci if (!toklen) 539d4afb5ceSopenharmony_ci return 0; 540d4afb5ceSopenharmony_ci 541d4afb5ceSopenharmony_ci if (toklen >= len) 542d4afb5ceSopenharmony_ci return -1; 543d4afb5ceSopenharmony_ci 544d4afb5ceSopenharmony_ci if (!wsi->http.ah) 545d4afb5ceSopenharmony_ci return -1; 546d4afb5ceSopenharmony_ci 547d4afb5ceSopenharmony_ci n = wsi->http.ah->frag_index[h]; 548d4afb5ceSopenharmony_ci if (!n) 549d4afb5ceSopenharmony_ci return 0; 550d4afb5ceSopenharmony_ci do { 551d4afb5ceSopenharmony_ci comma = (wsi->http.ah->frags[n].nfrag) ? 1 : 0; 552d4afb5ceSopenharmony_ci 553d4afb5ceSopenharmony_ci if (h == WSI_TOKEN_HTTP_URI_ARGS) 554d4afb5ceSopenharmony_ci lwsl_notice("%s: WSI_TOKEN_HTTP_URI_ARGS '%.*s'\n", 555d4afb5ceSopenharmony_ci __func__, (int)wsi->http.ah->frags[n].len, 556d4afb5ceSopenharmony_ci &wsi->http.ah->data[ 557d4afb5ceSopenharmony_ci wsi->http.ah->frags[n].offset]); 558d4afb5ceSopenharmony_ci 559d4afb5ceSopenharmony_ci if (wsi->http.ah->frags[n].len + comma >= len) { 560d4afb5ceSopenharmony_ci lwsl_notice("blowout len\n"); 561d4afb5ceSopenharmony_ci return -1; 562d4afb5ceSopenharmony_ci } 563d4afb5ceSopenharmony_ci strncpy(dst, &wsi->http.ah->data[wsi->http.ah->frags[n].offset], 564d4afb5ceSopenharmony_ci wsi->http.ah->frags[n].len); 565d4afb5ceSopenharmony_ci dst += wsi->http.ah->frags[n].len; 566d4afb5ceSopenharmony_ci len -= wsi->http.ah->frags[n].len; 567d4afb5ceSopenharmony_ci n = wsi->http.ah->frags[n].nfrag; 568d4afb5ceSopenharmony_ci 569d4afb5ceSopenharmony_ci /* 570d4afb5ceSopenharmony_ci * Note if you change this logic, take care about updating len 571d4afb5ceSopenharmony_ci * and make sure lws_hdr_total_length() gives the same resulting 572d4afb5ceSopenharmony_ci * length 573d4afb5ceSopenharmony_ci */ 574d4afb5ceSopenharmony_ci 575d4afb5ceSopenharmony_ci if (comma) { 576d4afb5ceSopenharmony_ci if (h == WSI_TOKEN_HTTP_COOKIE || 577d4afb5ceSopenharmony_ci h == WSI_TOKEN_HTTP_SET_COOKIE) 578d4afb5ceSopenharmony_ci *dst++ = ';'; 579d4afb5ceSopenharmony_ci else 580d4afb5ceSopenharmony_ci if (h == WSI_TOKEN_HTTP_URI_ARGS) 581d4afb5ceSopenharmony_ci *dst++ = '&'; 582d4afb5ceSopenharmony_ci else 583d4afb5ceSopenharmony_ci *dst++ = ','; 584d4afb5ceSopenharmony_ci len--; 585d4afb5ceSopenharmony_ci } 586d4afb5ceSopenharmony_ci 587d4afb5ceSopenharmony_ci } while (n); 588d4afb5ceSopenharmony_ci *dst = '\0'; 589d4afb5ceSopenharmony_ci 590d4afb5ceSopenharmony_ci if (h == WSI_TOKEN_HTTP_URI_ARGS) 591d4afb5ceSopenharmony_ci lwsl_err("%s: WSI_TOKEN_HTTP_URI_ARGS toklen %d\n", __func__, (int)toklen); 592d4afb5ceSopenharmony_ci 593d4afb5ceSopenharmony_ci return toklen; 594d4afb5ceSopenharmony_ci} 595d4afb5ceSopenharmony_ci 596d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 597d4afb5ceSopenharmony_ciint 598d4afb5ceSopenharmony_cilws_hdr_custom_length(struct lws *wsi, const char *name, int nlen) 599d4afb5ceSopenharmony_ci{ 600d4afb5ceSopenharmony_ci ah_data_idx_t ll; 601d4afb5ceSopenharmony_ci 602d4afb5ceSopenharmony_ci if (!wsi->http.ah || wsi->mux_substream) 603d4afb5ceSopenharmony_ci return -1; 604d4afb5ceSopenharmony_ci 605d4afb5ceSopenharmony_ci ll = wsi->http.ah->unk_ll_head; 606d4afb5ceSopenharmony_ci while (ll) { 607d4afb5ceSopenharmony_ci if (ll >= wsi->http.ah->data_length) 608d4afb5ceSopenharmony_ci return -1; 609d4afb5ceSopenharmony_ci if (nlen == lws_ser_ru16be( 610d4afb5ceSopenharmony_ci (uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]) && 611d4afb5ceSopenharmony_ci !strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], (unsigned int)nlen)) 612d4afb5ceSopenharmony_ci return lws_ser_ru16be( 613d4afb5ceSopenharmony_ci (uint8_t *)&wsi->http.ah->data[ll + UHO_VLEN]); 614d4afb5ceSopenharmony_ci 615d4afb5ceSopenharmony_ci ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]); 616d4afb5ceSopenharmony_ci } 617d4afb5ceSopenharmony_ci 618d4afb5ceSopenharmony_ci return -1; 619d4afb5ceSopenharmony_ci} 620d4afb5ceSopenharmony_ci 621d4afb5ceSopenharmony_ciint 622d4afb5ceSopenharmony_cilws_hdr_custom_copy(struct lws *wsi, char *dst, int len, const char *name, 623d4afb5ceSopenharmony_ci int nlen) 624d4afb5ceSopenharmony_ci{ 625d4afb5ceSopenharmony_ci ah_data_idx_t ll; 626d4afb5ceSopenharmony_ci int n; 627d4afb5ceSopenharmony_ci 628d4afb5ceSopenharmony_ci if (!wsi->http.ah || wsi->mux_substream) 629d4afb5ceSopenharmony_ci return -1; 630d4afb5ceSopenharmony_ci 631d4afb5ceSopenharmony_ci *dst = '\0'; 632d4afb5ceSopenharmony_ci 633d4afb5ceSopenharmony_ci ll = wsi->http.ah->unk_ll_head; 634d4afb5ceSopenharmony_ci while (ll) { 635d4afb5ceSopenharmony_ci if (ll >= wsi->http.ah->data_length) 636d4afb5ceSopenharmony_ci return -1; 637d4afb5ceSopenharmony_ci if (nlen == lws_ser_ru16be( 638d4afb5ceSopenharmony_ci (uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]) && 639d4afb5ceSopenharmony_ci !strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], (unsigned int)nlen)) { 640d4afb5ceSopenharmony_ci n = lws_ser_ru16be( 641d4afb5ceSopenharmony_ci (uint8_t *)&wsi->http.ah->data[ll + UHO_VLEN]); 642d4afb5ceSopenharmony_ci if (n + 1 > len) 643d4afb5ceSopenharmony_ci return -1; 644d4afb5ceSopenharmony_ci strncpy(dst, &wsi->http.ah->data[ll + UHO_NAME + (unsigned int)nlen], (unsigned int)n); 645d4afb5ceSopenharmony_ci dst[n] = '\0'; 646d4afb5ceSopenharmony_ci 647d4afb5ceSopenharmony_ci return n; 648d4afb5ceSopenharmony_ci } 649d4afb5ceSopenharmony_ci ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]); 650d4afb5ceSopenharmony_ci } 651d4afb5ceSopenharmony_ci 652d4afb5ceSopenharmony_ci return -1; 653d4afb5ceSopenharmony_ci} 654d4afb5ceSopenharmony_ci 655d4afb5ceSopenharmony_ciint 656d4afb5ceSopenharmony_cilws_hdr_custom_name_foreach(struct lws *wsi, lws_hdr_custom_fe_cb_t cb, 657d4afb5ceSopenharmony_ci void *custom) 658d4afb5ceSopenharmony_ci{ 659d4afb5ceSopenharmony_ci ah_data_idx_t ll; 660d4afb5ceSopenharmony_ci 661d4afb5ceSopenharmony_ci if (!wsi->http.ah || wsi->mux_substream) 662d4afb5ceSopenharmony_ci return -1; 663d4afb5ceSopenharmony_ci 664d4afb5ceSopenharmony_ci ll = wsi->http.ah->unk_ll_head; 665d4afb5ceSopenharmony_ci 666d4afb5ceSopenharmony_ci while (ll) { 667d4afb5ceSopenharmony_ci if (ll >= wsi->http.ah->data_length) 668d4afb5ceSopenharmony_ci return -1; 669d4afb5ceSopenharmony_ci 670d4afb5ceSopenharmony_ci cb(&wsi->http.ah->data[ll + UHO_NAME], 671d4afb5ceSopenharmony_ci lws_ser_ru16be((uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]), 672d4afb5ceSopenharmony_ci custom); 673d4afb5ceSopenharmony_ci 674d4afb5ceSopenharmony_ci ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]); 675d4afb5ceSopenharmony_ci } 676d4afb5ceSopenharmony_ci 677d4afb5ceSopenharmony_ci return 0; 678d4afb5ceSopenharmony_ci} 679d4afb5ceSopenharmony_ci#endif 680d4afb5ceSopenharmony_ci 681d4afb5ceSopenharmony_cichar *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h) 682d4afb5ceSopenharmony_ci{ 683d4afb5ceSopenharmony_ci int n; 684d4afb5ceSopenharmony_ci 685d4afb5ceSopenharmony_ci if (!wsi->http.ah) 686d4afb5ceSopenharmony_ci return NULL; 687d4afb5ceSopenharmony_ci 688d4afb5ceSopenharmony_ci n = wsi->http.ah->frag_index[h]; 689d4afb5ceSopenharmony_ci if (!n) 690d4afb5ceSopenharmony_ci return NULL; 691d4afb5ceSopenharmony_ci 692d4afb5ceSopenharmony_ci return wsi->http.ah->data + wsi->http.ah->frags[n].offset; 693d4afb5ceSopenharmony_ci} 694d4afb5ceSopenharmony_ci 695d4afb5ceSopenharmony_cistatic int LWS_WARN_UNUSED_RESULT 696d4afb5ceSopenharmony_cilws_pos_in_bounds(struct lws *wsi) 697d4afb5ceSopenharmony_ci{ 698d4afb5ceSopenharmony_ci if (!wsi->http.ah) 699d4afb5ceSopenharmony_ci return -1; 700d4afb5ceSopenharmony_ci 701d4afb5ceSopenharmony_ci if (wsi->http.ah->pos < 702d4afb5ceSopenharmony_ci (unsigned int)wsi->a.context->max_http_header_data) 703d4afb5ceSopenharmony_ci return 0; 704d4afb5ceSopenharmony_ci 705d4afb5ceSopenharmony_ci if ((int)wsi->http.ah->pos >= (int)wsi->a.context->max_http_header_data - 1) { 706d4afb5ceSopenharmony_ci lwsl_err("Ran out of header data space\n"); 707d4afb5ceSopenharmony_ci return 1; 708d4afb5ceSopenharmony_ci } 709d4afb5ceSopenharmony_ci 710d4afb5ceSopenharmony_ci /* 711d4afb5ceSopenharmony_ci * with these tests everywhere, it should never be able to exceed 712d4afb5ceSopenharmony_ci * the limit, only meet it 713d4afb5ceSopenharmony_ci */ 714d4afb5ceSopenharmony_ci lwsl_err("%s: pos %ld, limit %ld\n", __func__, 715d4afb5ceSopenharmony_ci (unsigned long)wsi->http.ah->pos, 716d4afb5ceSopenharmony_ci (unsigned long)wsi->a.context->max_http_header_data); 717d4afb5ceSopenharmony_ci assert(0); 718d4afb5ceSopenharmony_ci 719d4afb5ceSopenharmony_ci return 1; 720d4afb5ceSopenharmony_ci} 721d4afb5ceSopenharmony_ci 722d4afb5ceSopenharmony_ciint LWS_WARN_UNUSED_RESULT 723d4afb5ceSopenharmony_cilws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s) 724d4afb5ceSopenharmony_ci{ 725d4afb5ceSopenharmony_ci if (!*s) { 726d4afb5ceSopenharmony_ci /* 727d4afb5ceSopenharmony_ci * If we get an empty string, then remove any entry for the 728d4afb5ceSopenharmony_ci * header 729d4afb5ceSopenharmony_ci */ 730d4afb5ceSopenharmony_ci wsi->http.ah->frag_index[h] = 0; 731d4afb5ceSopenharmony_ci 732d4afb5ceSopenharmony_ci return 0; 733d4afb5ceSopenharmony_ci } 734d4afb5ceSopenharmony_ci 735d4afb5ceSopenharmony_ci wsi->http.ah->nfrag++; 736d4afb5ceSopenharmony_ci if (wsi->http.ah->nfrag == LWS_ARRAY_SIZE(wsi->http.ah->frags)) { 737d4afb5ceSopenharmony_ci lwsl_warn("More hdr frags than we can deal with, dropping\n"); 738d4afb5ceSopenharmony_ci return -1; 739d4afb5ceSopenharmony_ci } 740d4afb5ceSopenharmony_ci 741d4afb5ceSopenharmony_ci wsi->http.ah->frag_index[h] = wsi->http.ah->nfrag; 742d4afb5ceSopenharmony_ci 743d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].offset = wsi->http.ah->pos; 744d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].len = 0; 745d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].nfrag = 0; 746d4afb5ceSopenharmony_ci 747d4afb5ceSopenharmony_ci do { 748d4afb5ceSopenharmony_ci if (lws_pos_in_bounds(wsi)) 749d4afb5ceSopenharmony_ci return -1; 750d4afb5ceSopenharmony_ci 751d4afb5ceSopenharmony_ci wsi->http.ah->data[wsi->http.ah->pos++] = *s; 752d4afb5ceSopenharmony_ci if (*s) 753d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].len++; 754d4afb5ceSopenharmony_ci } while (*s++); 755d4afb5ceSopenharmony_ci 756d4afb5ceSopenharmony_ci return 0; 757d4afb5ceSopenharmony_ci} 758d4afb5ceSopenharmony_ci 759d4afb5ceSopenharmony_cistatic int LWS_WARN_UNUSED_RESULT 760d4afb5ceSopenharmony_ciissue_char(struct lws *wsi, unsigned char c) 761d4afb5ceSopenharmony_ci{ 762d4afb5ceSopenharmony_ci unsigned short frag_len; 763d4afb5ceSopenharmony_ci 764d4afb5ceSopenharmony_ci if (lws_pos_in_bounds(wsi)) 765d4afb5ceSopenharmony_ci return -1; 766d4afb5ceSopenharmony_ci 767d4afb5ceSopenharmony_ci frag_len = wsi->http.ah->frags[wsi->http.ah->nfrag].len; 768d4afb5ceSopenharmony_ci /* 769d4afb5ceSopenharmony_ci * If we haven't hit the token limit, just copy the character into 770d4afb5ceSopenharmony_ci * the header 771d4afb5ceSopenharmony_ci */ 772d4afb5ceSopenharmony_ci if (!wsi->http.ah->current_token_limit || 773d4afb5ceSopenharmony_ci frag_len < wsi->http.ah->current_token_limit) { 774d4afb5ceSopenharmony_ci wsi->http.ah->data[wsi->http.ah->pos++] = (char)c; 775d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].len++; 776d4afb5ceSopenharmony_ci return 0; 777d4afb5ceSopenharmony_ci } 778d4afb5ceSopenharmony_ci 779d4afb5ceSopenharmony_ci /* Insert a null character when we *hit* the limit: */ 780d4afb5ceSopenharmony_ci if (frag_len == wsi->http.ah->current_token_limit) { 781d4afb5ceSopenharmony_ci if (lws_pos_in_bounds(wsi)) 782d4afb5ceSopenharmony_ci return -1; 783d4afb5ceSopenharmony_ci 784d4afb5ceSopenharmony_ci wsi->http.ah->data[wsi->http.ah->pos++] = '\0'; 785d4afb5ceSopenharmony_ci lwsl_warn("header %li exceeds limit %ld\n", 786d4afb5ceSopenharmony_ci (long)wsi->http.ah->parser_state, 787d4afb5ceSopenharmony_ci (long)wsi->http.ah->current_token_limit); 788d4afb5ceSopenharmony_ci } 789d4afb5ceSopenharmony_ci 790d4afb5ceSopenharmony_ci return 1; 791d4afb5ceSopenharmony_ci} 792d4afb5ceSopenharmony_ci 793d4afb5ceSopenharmony_ciint 794d4afb5ceSopenharmony_cilws_parse_urldecode(struct lws *wsi, uint8_t *_c) 795d4afb5ceSopenharmony_ci{ 796d4afb5ceSopenharmony_ci struct allocated_headers *ah = wsi->http.ah; 797d4afb5ceSopenharmony_ci unsigned int enc = 0; 798d4afb5ceSopenharmony_ci uint8_t c = *_c; 799d4afb5ceSopenharmony_ci 800d4afb5ceSopenharmony_ci // lwsl_notice("ah->ups %d\n", ah->ups); 801d4afb5ceSopenharmony_ci 802d4afb5ceSopenharmony_ci /* 803d4afb5ceSopenharmony_ci * PRIORITY 1 804d4afb5ceSopenharmony_ci * special URI processing... convert %xx 805d4afb5ceSopenharmony_ci */ 806d4afb5ceSopenharmony_ci switch (ah->ues) { 807d4afb5ceSopenharmony_ci case URIES_IDLE: 808d4afb5ceSopenharmony_ci if (c == '%') { 809d4afb5ceSopenharmony_ci ah->ues = URIES_SEEN_PERCENT; 810d4afb5ceSopenharmony_ci goto swallow; 811d4afb5ceSopenharmony_ci } 812d4afb5ceSopenharmony_ci break; 813d4afb5ceSopenharmony_ci case URIES_SEEN_PERCENT: 814d4afb5ceSopenharmony_ci if (char_to_hex((char)c) < 0) 815d4afb5ceSopenharmony_ci /* illegal post-% char */ 816d4afb5ceSopenharmony_ci goto forbid; 817d4afb5ceSopenharmony_ci 818d4afb5ceSopenharmony_ci ah->esc_stash = (char)c; 819d4afb5ceSopenharmony_ci ah->ues = URIES_SEEN_PERCENT_H1; 820d4afb5ceSopenharmony_ci goto swallow; 821d4afb5ceSopenharmony_ci 822d4afb5ceSopenharmony_ci case URIES_SEEN_PERCENT_H1: 823d4afb5ceSopenharmony_ci if (char_to_hex((char)c) < 0) 824d4afb5ceSopenharmony_ci /* illegal post-% char */ 825d4afb5ceSopenharmony_ci goto forbid; 826d4afb5ceSopenharmony_ci 827d4afb5ceSopenharmony_ci *_c = (uint8_t)(unsigned int)((char_to_hex(ah->esc_stash) << 4) | 828d4afb5ceSopenharmony_ci char_to_hex((char)c)); 829d4afb5ceSopenharmony_ci c = *_c; 830d4afb5ceSopenharmony_ci enc = 1; 831d4afb5ceSopenharmony_ci ah->ues = URIES_IDLE; 832d4afb5ceSopenharmony_ci break; 833d4afb5ceSopenharmony_ci } 834d4afb5ceSopenharmony_ci 835d4afb5ceSopenharmony_ci /* 836d4afb5ceSopenharmony_ci * PRIORITY 2 837d4afb5ceSopenharmony_ci * special URI processing... 838d4afb5ceSopenharmony_ci * convert /.. or /... or /../ etc to / 839d4afb5ceSopenharmony_ci * convert /./ to / 840d4afb5ceSopenharmony_ci * convert // or /// etc to / 841d4afb5ceSopenharmony_ci * leave /.dir or whatever alone 842d4afb5ceSopenharmony_ci */ 843d4afb5ceSopenharmony_ci 844d4afb5ceSopenharmony_ci if (!c && (!ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] || 845d4afb5ceSopenharmony_ci !ah->post_literal_equal)) { 846d4afb5ceSopenharmony_ci /* 847d4afb5ceSopenharmony_ci * Since user code is typically going to parse the path using 848d4afb5ceSopenharmony_ci * NUL-terminated apis, it's too dangerous to allow NUL 849d4afb5ceSopenharmony_ci * injection here. 850d4afb5ceSopenharmony_ci * 851d4afb5ceSopenharmony_ci * It's allowed in the urlargs, because the apis to access 852d4afb5ceSopenharmony_ci * those only allow retreival with explicit length. 853d4afb5ceSopenharmony_ci */ 854d4afb5ceSopenharmony_ci lwsl_warn("%s: saw NUL outside of uri args\n", __func__); 855d4afb5ceSopenharmony_ci return -1; 856d4afb5ceSopenharmony_ci } 857d4afb5ceSopenharmony_ci 858d4afb5ceSopenharmony_ci switch (ah->ups) { 859d4afb5ceSopenharmony_ci case URIPS_IDLE: 860d4afb5ceSopenharmony_ci 861d4afb5ceSopenharmony_ci /* genuine delimiter */ 862d4afb5ceSopenharmony_ci if ((c == '&' || c == ';') && !enc) { 863d4afb5ceSopenharmony_ci if (issue_char(wsi, '\0') < 0) 864d4afb5ceSopenharmony_ci return -1; 865d4afb5ceSopenharmony_ci /* don't account for it */ 866d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].len--; 867d4afb5ceSopenharmony_ci /* link to next fragment */ 868d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].nfrag = (uint8_t)(ah->nfrag + 1); 869d4afb5ceSopenharmony_ci ah->nfrag++; 870d4afb5ceSopenharmony_ci if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags)) 871d4afb5ceSopenharmony_ci goto excessive; 872d4afb5ceSopenharmony_ci /* start next fragment after the & */ 873d4afb5ceSopenharmony_ci ah->post_literal_equal = 0; 874d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].offset = ++ah->pos; 875d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].len = 0; 876d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].nfrag = 0; 877d4afb5ceSopenharmony_ci goto swallow; 878d4afb5ceSopenharmony_ci } 879d4afb5ceSopenharmony_ci /* uriencoded = in the name part, disallow */ 880d4afb5ceSopenharmony_ci if (c == '=' && enc && 881d4afb5ceSopenharmony_ci ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] && 882d4afb5ceSopenharmony_ci !ah->post_literal_equal) { 883d4afb5ceSopenharmony_ci c = '_'; 884d4afb5ceSopenharmony_ci *_c =c; 885d4afb5ceSopenharmony_ci } 886d4afb5ceSopenharmony_ci 887d4afb5ceSopenharmony_ci /* after the real =, we don't care how many = */ 888d4afb5ceSopenharmony_ci if (c == '=' && !enc) 889d4afb5ceSopenharmony_ci ah->post_literal_equal = 1; 890d4afb5ceSopenharmony_ci 891d4afb5ceSopenharmony_ci /* + to space */ 892d4afb5ceSopenharmony_ci if (c == '+' && !enc) { 893d4afb5ceSopenharmony_ci c = ' '; 894d4afb5ceSopenharmony_ci *_c = c; 895d4afb5ceSopenharmony_ci } 896d4afb5ceSopenharmony_ci /* issue the first / always */ 897d4afb5ceSopenharmony_ci if (c == '/' && !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) 898d4afb5ceSopenharmony_ci ah->ups = URIPS_SEEN_SLASH; 899d4afb5ceSopenharmony_ci break; 900d4afb5ceSopenharmony_ci case URIPS_SEEN_SLASH: 901d4afb5ceSopenharmony_ci /* swallow subsequent slashes */ 902d4afb5ceSopenharmony_ci if (c == '/') 903d4afb5ceSopenharmony_ci goto swallow; 904d4afb5ceSopenharmony_ci /* track and swallow the first . after / */ 905d4afb5ceSopenharmony_ci if (c == '.') { 906d4afb5ceSopenharmony_ci ah->ups = URIPS_SEEN_SLASH_DOT; 907d4afb5ceSopenharmony_ci goto swallow; 908d4afb5ceSopenharmony_ci } 909d4afb5ceSopenharmony_ci ah->ups = URIPS_IDLE; 910d4afb5ceSopenharmony_ci break; 911d4afb5ceSopenharmony_ci case URIPS_SEEN_SLASH_DOT: 912d4afb5ceSopenharmony_ci /* swallow second . */ 913d4afb5ceSopenharmony_ci if (c == '.') { 914d4afb5ceSopenharmony_ci ah->ups = URIPS_SEEN_SLASH_DOT_DOT; 915d4afb5ceSopenharmony_ci goto swallow; 916d4afb5ceSopenharmony_ci } 917d4afb5ceSopenharmony_ci /* change /./ to / */ 918d4afb5ceSopenharmony_ci if (c == '/') { 919d4afb5ceSopenharmony_ci ah->ups = URIPS_SEEN_SLASH; 920d4afb5ceSopenharmony_ci goto swallow; 921d4afb5ceSopenharmony_ci } 922d4afb5ceSopenharmony_ci /* it was like /.dir ... regurgitate the . */ 923d4afb5ceSopenharmony_ci ah->ups = URIPS_IDLE; 924d4afb5ceSopenharmony_ci if (issue_char(wsi, '.') < 0) 925d4afb5ceSopenharmony_ci return -1; 926d4afb5ceSopenharmony_ci break; 927d4afb5ceSopenharmony_ci 928d4afb5ceSopenharmony_ci case URIPS_SEEN_SLASH_DOT_DOT: 929d4afb5ceSopenharmony_ci 930d4afb5ceSopenharmony_ci /* /../ or /..[End of URI] --> backup to last / */ 931d4afb5ceSopenharmony_ci if (c == '/' || c == '?') { 932d4afb5ceSopenharmony_ci /* 933d4afb5ceSopenharmony_ci * back up one dir level if possible 934d4afb5ceSopenharmony_ci * safe against header fragmentation because 935d4afb5ceSopenharmony_ci * the method URI can only be in 1 fragment 936d4afb5ceSopenharmony_ci */ 937d4afb5ceSopenharmony_ci if (ah->frags[ah->nfrag].len > 2) { 938d4afb5ceSopenharmony_ci ah->pos--; 939d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].len--; 940d4afb5ceSopenharmony_ci do { 941d4afb5ceSopenharmony_ci ah->pos--; 942d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].len--; 943d4afb5ceSopenharmony_ci } while (ah->frags[ah->nfrag].len > 1 && 944d4afb5ceSopenharmony_ci ah->data[ah->pos] != '/'); 945d4afb5ceSopenharmony_ci } 946d4afb5ceSopenharmony_ci ah->ups = URIPS_SEEN_SLASH; 947d4afb5ceSopenharmony_ci if (ah->frags[ah->nfrag].len > 1) 948d4afb5ceSopenharmony_ci break; 949d4afb5ceSopenharmony_ci goto swallow; 950d4afb5ceSopenharmony_ci } 951d4afb5ceSopenharmony_ci 952d4afb5ceSopenharmony_ci /* /..[^/] ... regurgitate and allow */ 953d4afb5ceSopenharmony_ci 954d4afb5ceSopenharmony_ci if (issue_char(wsi, '.') < 0) 955d4afb5ceSopenharmony_ci return -1; 956d4afb5ceSopenharmony_ci if (issue_char(wsi, '.') < 0) 957d4afb5ceSopenharmony_ci return -1; 958d4afb5ceSopenharmony_ci ah->ups = URIPS_IDLE; 959d4afb5ceSopenharmony_ci break; 960d4afb5ceSopenharmony_ci } 961d4afb5ceSopenharmony_ci 962d4afb5ceSopenharmony_ci if (c == '?' && !enc && 963d4afb5ceSopenharmony_ci !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI args */ 964d4afb5ceSopenharmony_ci if (ah->ues != URIES_IDLE) 965d4afb5ceSopenharmony_ci goto forbid; 966d4afb5ceSopenharmony_ci 967d4afb5ceSopenharmony_ci /* seal off uri header */ 968d4afb5ceSopenharmony_ci if (issue_char(wsi, '\0') < 0) 969d4afb5ceSopenharmony_ci return -1; 970d4afb5ceSopenharmony_ci 971d4afb5ceSopenharmony_ci /* don't account for it */ 972d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].len--; 973d4afb5ceSopenharmony_ci 974d4afb5ceSopenharmony_ci /* move to using WSI_TOKEN_HTTP_URI_ARGS */ 975d4afb5ceSopenharmony_ci ah->nfrag++; 976d4afb5ceSopenharmony_ci if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags)) 977d4afb5ceSopenharmony_ci goto excessive; 978d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].offset = ++ah->pos; 979d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].len = 0; 980d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].nfrag = 0; 981d4afb5ceSopenharmony_ci 982d4afb5ceSopenharmony_ci ah->post_literal_equal = 0; 983d4afb5ceSopenharmony_ci ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] = ah->nfrag; 984d4afb5ceSopenharmony_ci ah->ups = URIPS_IDLE; 985d4afb5ceSopenharmony_ci goto swallow; 986d4afb5ceSopenharmony_ci } 987d4afb5ceSopenharmony_ci 988d4afb5ceSopenharmony_ci return LPUR_CONTINUE; 989d4afb5ceSopenharmony_ci 990d4afb5ceSopenharmony_ciswallow: 991d4afb5ceSopenharmony_ci return LPUR_SWALLOW; 992d4afb5ceSopenharmony_ci 993d4afb5ceSopenharmony_ciforbid: 994d4afb5ceSopenharmony_ci return LPUR_FORBID; 995d4afb5ceSopenharmony_ci 996d4afb5ceSopenharmony_ciexcessive: 997d4afb5ceSopenharmony_ci return LPUR_EXCESSIVE; 998d4afb5ceSopenharmony_ci} 999d4afb5ceSopenharmony_ci 1000d4afb5ceSopenharmony_cistatic const unsigned char methods[] = { 1001d4afb5ceSopenharmony_ci WSI_TOKEN_GET_URI, 1002d4afb5ceSopenharmony_ci WSI_TOKEN_POST_URI, 1003d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 1004d4afb5ceSopenharmony_ci WSI_TOKEN_OPTIONS_URI, 1005d4afb5ceSopenharmony_ci WSI_TOKEN_PUT_URI, 1006d4afb5ceSopenharmony_ci WSI_TOKEN_PATCH_URI, 1007d4afb5ceSopenharmony_ci WSI_TOKEN_DELETE_URI, 1008d4afb5ceSopenharmony_ci#endif 1009d4afb5ceSopenharmony_ci WSI_TOKEN_CONNECT, 1010d4afb5ceSopenharmony_ci WSI_TOKEN_HEAD_URI, 1011d4afb5ceSopenharmony_ci}; 1012d4afb5ceSopenharmony_ci 1013d4afb5ceSopenharmony_ci/* 1014d4afb5ceSopenharmony_ci * possible returns:, -1 fail, 0 ok or 2, transition to raw 1015d4afb5ceSopenharmony_ci */ 1016d4afb5ceSopenharmony_ci 1017d4afb5ceSopenharmony_cilws_parser_return_t LWS_WARN_UNUSED_RESULT 1018d4afb5ceSopenharmony_cilws_parse(struct lws *wsi, unsigned char *buf, int *len) 1019d4afb5ceSopenharmony_ci{ 1020d4afb5ceSopenharmony_ci struct allocated_headers *ah = wsi->http.ah; 1021d4afb5ceSopenharmony_ci struct lws_context *context = wsi->a.context; 1022d4afb5ceSopenharmony_ci unsigned int n, m; 1023d4afb5ceSopenharmony_ci unsigned char c; 1024d4afb5ceSopenharmony_ci int r, pos; 1025d4afb5ceSopenharmony_ci 1026d4afb5ceSopenharmony_ci assert(wsi->http.ah); 1027d4afb5ceSopenharmony_ci 1028d4afb5ceSopenharmony_ci do { 1029d4afb5ceSopenharmony_ci (*len)--; 1030d4afb5ceSopenharmony_ci c = *buf++; 1031d4afb5ceSopenharmony_ci 1032d4afb5ceSopenharmony_ci switch (ah->parser_state) { 1033d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 1034d4afb5ceSopenharmony_ci case WSI_TOKEN_UNKNOWN_VALUE_PART: 1035d4afb5ceSopenharmony_ci 1036d4afb5ceSopenharmony_ci if (c == '\r') 1037d4afb5ceSopenharmony_ci break; 1038d4afb5ceSopenharmony_ci if (c == '\n') { 1039d4afb5ceSopenharmony_ci lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos + 2], 1040d4afb5ceSopenharmony_ci (uint16_t)(ah->pos - ah->unk_value_pos)); 1041d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_NAME_PART; 1042d4afb5ceSopenharmony_ci ah->unk_pos = 0; 1043d4afb5ceSopenharmony_ci ah->lextable_pos = 0; 1044d4afb5ceSopenharmony_ci break; 1045d4afb5ceSopenharmony_ci } 1046d4afb5ceSopenharmony_ci 1047d4afb5ceSopenharmony_ci /* trim leading whitespace */ 1048d4afb5ceSopenharmony_ci if (ah->pos != ah->unk_value_pos || 1049d4afb5ceSopenharmony_ci (c != ' ' && c != '\t')) { 1050d4afb5ceSopenharmony_ci 1051d4afb5ceSopenharmony_ci if (lws_pos_in_bounds(wsi)) 1052d4afb5ceSopenharmony_ci return LPR_FAIL; 1053d4afb5ceSopenharmony_ci 1054d4afb5ceSopenharmony_ci ah->data[ah->pos++] = (char)c; 1055d4afb5ceSopenharmony_ci } 1056d4afb5ceSopenharmony_ci pos = ah->lextable_pos; 1057d4afb5ceSopenharmony_ci break; 1058d4afb5ceSopenharmony_ci#endif 1059d4afb5ceSopenharmony_ci default: 1060d4afb5ceSopenharmony_ci 1061d4afb5ceSopenharmony_ci lwsl_parser("WSI_TOK_(%d) '%c'\n", ah->parser_state, c); 1062d4afb5ceSopenharmony_ci 1063d4afb5ceSopenharmony_ci /* collect into malloc'd buffers */ 1064d4afb5ceSopenharmony_ci /* optional initial space swallow */ 1065d4afb5ceSopenharmony_ci if (!ah->frags[ah->frag_index[ah->parser_state]].len && 1066d4afb5ceSopenharmony_ci c == ' ') 1067d4afb5ceSopenharmony_ci break; 1068d4afb5ceSopenharmony_ci 1069d4afb5ceSopenharmony_ci for (m = 0; m < LWS_ARRAY_SIZE(methods); m++) 1070d4afb5ceSopenharmony_ci if (ah->parser_state == methods[m]) 1071d4afb5ceSopenharmony_ci break; 1072d4afb5ceSopenharmony_ci if (m == LWS_ARRAY_SIZE(methods)) 1073d4afb5ceSopenharmony_ci /* it was not any of the methods */ 1074d4afb5ceSopenharmony_ci goto check_eol; 1075d4afb5ceSopenharmony_ci 1076d4afb5ceSopenharmony_ci /* special URI processing... end at space */ 1077d4afb5ceSopenharmony_ci 1078d4afb5ceSopenharmony_ci if (c == ' ') { 1079d4afb5ceSopenharmony_ci /* enforce starting with / */ 1080d4afb5ceSopenharmony_ci if (!ah->frags[ah->nfrag].len) 1081d4afb5ceSopenharmony_ci if (issue_char(wsi, '/') < 0) 1082d4afb5ceSopenharmony_ci return LPR_FAIL; 1083d4afb5ceSopenharmony_ci 1084d4afb5ceSopenharmony_ci if (ah->ups == URIPS_SEEN_SLASH_DOT_DOT) { 1085d4afb5ceSopenharmony_ci /* 1086d4afb5ceSopenharmony_ci * back up one dir level if possible 1087d4afb5ceSopenharmony_ci * safe against header fragmentation 1088d4afb5ceSopenharmony_ci * because the method URI can only be 1089d4afb5ceSopenharmony_ci * in 1 fragment 1090d4afb5ceSopenharmony_ci */ 1091d4afb5ceSopenharmony_ci if (ah->frags[ah->nfrag].len > 2) { 1092d4afb5ceSopenharmony_ci ah->pos--; 1093d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].len--; 1094d4afb5ceSopenharmony_ci do { 1095d4afb5ceSopenharmony_ci ah->pos--; 1096d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].len--; 1097d4afb5ceSopenharmony_ci } while (ah->frags[ah->nfrag].len > 1 && 1098d4afb5ceSopenharmony_ci ah->data[ah->pos] != '/'); 1099d4afb5ceSopenharmony_ci } 1100d4afb5ceSopenharmony_ci } 1101d4afb5ceSopenharmony_ci 1102d4afb5ceSopenharmony_ci /* begin parsing HTTP version: */ 1103d4afb5ceSopenharmony_ci if (issue_char(wsi, '\0') < 0) 1104d4afb5ceSopenharmony_ci return LPR_FAIL; 1105d4afb5ceSopenharmony_ci /* don't account for it */ 1106d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].len--; 1107d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_HTTP; 1108d4afb5ceSopenharmony_ci goto start_fragment; 1109d4afb5ceSopenharmony_ci } 1110d4afb5ceSopenharmony_ci 1111d4afb5ceSopenharmony_ci r = lws_parse_urldecode(wsi, &c); 1112d4afb5ceSopenharmony_ci switch (r) { 1113d4afb5ceSopenharmony_ci case LPUR_CONTINUE: 1114d4afb5ceSopenharmony_ci break; 1115d4afb5ceSopenharmony_ci case LPUR_SWALLOW: 1116d4afb5ceSopenharmony_ci goto swallow; 1117d4afb5ceSopenharmony_ci case LPUR_FORBID: 1118d4afb5ceSopenharmony_ci goto forbid; 1119d4afb5ceSopenharmony_ci case LPUR_EXCESSIVE: 1120d4afb5ceSopenharmony_ci goto excessive; 1121d4afb5ceSopenharmony_ci default: 1122d4afb5ceSopenharmony_ci return LPR_FAIL; 1123d4afb5ceSopenharmony_ci } 1124d4afb5ceSopenharmony_cicheck_eol: 1125d4afb5ceSopenharmony_ci /* bail at EOL */ 1126d4afb5ceSopenharmony_ci if (ah->parser_state != WSI_TOKEN_CHALLENGE && 1127d4afb5ceSopenharmony_ci (c == '\x0d' || c == '\x0a')) { 1128d4afb5ceSopenharmony_ci if (ah->ues != URIES_IDLE) 1129d4afb5ceSopenharmony_ci goto forbid; 1130d4afb5ceSopenharmony_ci 1131d4afb5ceSopenharmony_ci if (c == '\x0a') { 1132d4afb5ceSopenharmony_ci /* broken peer */ 1133d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_NAME_PART; 1134d4afb5ceSopenharmony_ci ah->unk_pos = 0; 1135d4afb5ceSopenharmony_ci ah->lextable_pos = 0; 1136d4afb5ceSopenharmony_ci } else 1137d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR; 1138d4afb5ceSopenharmony_ci 1139d4afb5ceSopenharmony_ci c = '\0'; 1140d4afb5ceSopenharmony_ci lwsl_parser("*\n"); 1141d4afb5ceSopenharmony_ci } 1142d4afb5ceSopenharmony_ci 1143d4afb5ceSopenharmony_ci n = (unsigned int)issue_char(wsi, c); 1144d4afb5ceSopenharmony_ci if ((int)n < 0) 1145d4afb5ceSopenharmony_ci return LPR_FAIL; 1146d4afb5ceSopenharmony_ci if (n > 0) 1147d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_SKIPPING; 1148d4afb5ceSopenharmony_ci else { 1149d4afb5ceSopenharmony_ci /* 1150d4afb5ceSopenharmony_ci * Explicit zeroes are legal in URI ARGS. 1151d4afb5ceSopenharmony_ci * They can only exist as a safety terminator 1152d4afb5ceSopenharmony_ci * after the valid part of the token contents 1153d4afb5ceSopenharmony_ci * for other types. 1154d4afb5ceSopenharmony_ci */ 1155d4afb5ceSopenharmony_ci if (!c && ah->parser_state != WSI_TOKEN_HTTP_URI_ARGS) 1156d4afb5ceSopenharmony_ci /* don't account for safety terminator */ 1157d4afb5ceSopenharmony_ci wsi->http.ah->frags[wsi->http.ah->nfrag].len--; 1158d4afb5ceSopenharmony_ci } 1159d4afb5ceSopenharmony_ci 1160d4afb5ceSopenharmony_ciswallow: 1161d4afb5ceSopenharmony_ci /* per-protocol end of headers management */ 1162d4afb5ceSopenharmony_ci 1163d4afb5ceSopenharmony_ci if (ah->parser_state == WSI_TOKEN_CHALLENGE) 1164d4afb5ceSopenharmony_ci goto set_parsing_complete; 1165d4afb5ceSopenharmony_ci break; 1166d4afb5ceSopenharmony_ci 1167d4afb5ceSopenharmony_ci /* collecting and checking a name part */ 1168d4afb5ceSopenharmony_ci case WSI_TOKEN_NAME_PART: 1169d4afb5ceSopenharmony_ci lwsl_parser("WSI_TOKEN_NAME_PART '%c' 0x%02X " 1170d4afb5ceSopenharmony_ci "(role=0x%lx) " 1171d4afb5ceSopenharmony_ci "wsi->lextable_pos=%d\n", c, c, 1172d4afb5ceSopenharmony_ci (unsigned long)lwsi_role(wsi), 1173d4afb5ceSopenharmony_ci ah->lextable_pos); 1174d4afb5ceSopenharmony_ci 1175d4afb5ceSopenharmony_ci if (!ah->unk_pos && c == '\x0a') 1176d4afb5ceSopenharmony_ci /* broken peer */ 1177d4afb5ceSopenharmony_ci goto set_parsing_complete; 1178d4afb5ceSopenharmony_ci 1179d4afb5ceSopenharmony_ci if (c >= 'A' && c <= 'Z') 1180d4afb5ceSopenharmony_ci c = (unsigned char)(c + 'a' - 'A'); 1181d4afb5ceSopenharmony_ci /* 1182d4afb5ceSopenharmony_ci * ...in case it's an unknown header, speculatively 1183d4afb5ceSopenharmony_ci * store it as the name comes in. If we recognize it as 1184d4afb5ceSopenharmony_ci * a known header, we'll snip this. 1185d4afb5ceSopenharmony_ci */ 1186d4afb5ceSopenharmony_ci 1187d4afb5ceSopenharmony_ci if (!wsi->mux_substream && !ah->unk_pos) { 1188d4afb5ceSopenharmony_ci ah->unk_pos = ah->pos; 1189d4afb5ceSopenharmony_ci 1190d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 1191d4afb5ceSopenharmony_ci /* 1192d4afb5ceSopenharmony_ci * Prepare new unknown header linked-list entry 1193d4afb5ceSopenharmony_ci * 1194d4afb5ceSopenharmony_ci * - 16-bit BE: name part length 1195d4afb5ceSopenharmony_ci * - 16-bit BE: value part length 1196d4afb5ceSopenharmony_ci * - 32-bit BE: data offset of next, or 0 1197d4afb5ceSopenharmony_ci */ 1198d4afb5ceSopenharmony_ci for (n = 0; n < 8; n++) 1199d4afb5ceSopenharmony_ci if (!lws_pos_in_bounds(wsi)) 1200d4afb5ceSopenharmony_ci ah->data[ah->pos++] = 0; 1201d4afb5ceSopenharmony_ci#endif 1202d4afb5ceSopenharmony_ci } 1203d4afb5ceSopenharmony_ci 1204d4afb5ceSopenharmony_ci if (lws_pos_in_bounds(wsi)) 1205d4afb5ceSopenharmony_ci return LPR_FAIL; 1206d4afb5ceSopenharmony_ci 1207d4afb5ceSopenharmony_ci ah->data[ah->pos++] = (char)c; 1208d4afb5ceSopenharmony_ci pos = ah->lextable_pos; 1209d4afb5ceSopenharmony_ci 1210d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 1211d4afb5ceSopenharmony_ci if (!wsi->mux_substream && pos < 0 && c == ':') { 1212d4afb5ceSopenharmony_ci#if defined(_DEBUG) 1213d4afb5ceSopenharmony_ci char dotstar[64]; 1214d4afb5ceSopenharmony_ci int uhlen; 1215d4afb5ceSopenharmony_ci#endif 1216d4afb5ceSopenharmony_ci 1217d4afb5ceSopenharmony_ci /* 1218d4afb5ceSopenharmony_ci * process unknown headers 1219d4afb5ceSopenharmony_ci * 1220d4afb5ceSopenharmony_ci * register us in the unknown hdr ll 1221d4afb5ceSopenharmony_ci */ 1222d4afb5ceSopenharmony_ci 1223d4afb5ceSopenharmony_ci if (!ah->unk_ll_head) 1224d4afb5ceSopenharmony_ci ah->unk_ll_head = ah->unk_pos; 1225d4afb5ceSopenharmony_ci 1226d4afb5ceSopenharmony_ci if (ah->unk_ll_tail) 1227d4afb5ceSopenharmony_ci lws_ser_wu32be( 1228d4afb5ceSopenharmony_ci (uint8_t *)&ah->data[ah->unk_ll_tail + UHO_LL], 1229d4afb5ceSopenharmony_ci ah->unk_pos); 1230d4afb5ceSopenharmony_ci 1231d4afb5ceSopenharmony_ci ah->unk_ll_tail = ah->unk_pos; 1232d4afb5ceSopenharmony_ci 1233d4afb5ceSopenharmony_ci#if defined(_DEBUG) 1234d4afb5ceSopenharmony_ci uhlen = (int)(ah->pos - (ah->unk_pos + UHO_NAME)); 1235d4afb5ceSopenharmony_ci lws_strnncpy(dotstar, 1236d4afb5ceSopenharmony_ci &ah->data[ah->unk_pos + UHO_NAME], 1237d4afb5ceSopenharmony_ci uhlen, sizeof(dotstar)); 1238d4afb5ceSopenharmony_ci lwsl_debug("%s: unk header %d '%s'\n", 1239d4afb5ceSopenharmony_ci __func__, 1240d4afb5ceSopenharmony_ci ah->pos - (ah->unk_pos + UHO_NAME), 1241d4afb5ceSopenharmony_ci dotstar); 1242d4afb5ceSopenharmony_ci#endif 1243d4afb5ceSopenharmony_ci 1244d4afb5ceSopenharmony_ci /* set the unknown header name part length */ 1245d4afb5ceSopenharmony_ci 1246d4afb5ceSopenharmony_ci lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos], 1247d4afb5ceSopenharmony_ci (uint16_t)((ah->pos - ah->unk_pos) - UHO_NAME)); 1248d4afb5ceSopenharmony_ci 1249d4afb5ceSopenharmony_ci ah->unk_value_pos = ah->pos; 1250d4afb5ceSopenharmony_ci 1251d4afb5ceSopenharmony_ci /* 1252d4afb5ceSopenharmony_ci * collect whatever's coming for the unknown header 1253d4afb5ceSopenharmony_ci * argument until the next CRLF 1254d4afb5ceSopenharmony_ci */ 1255d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_UNKNOWN_VALUE_PART; 1256d4afb5ceSopenharmony_ci break; 1257d4afb5ceSopenharmony_ci } 1258d4afb5ceSopenharmony_ci#endif 1259d4afb5ceSopenharmony_ci if (pos < 0) 1260d4afb5ceSopenharmony_ci break; 1261d4afb5ceSopenharmony_ci 1262d4afb5ceSopenharmony_ci while (1) { 1263d4afb5ceSopenharmony_ci if (lextable_h1[pos] & (1 << 7)) { 1264d4afb5ceSopenharmony_ci /* 1-byte, fail on mismatch */ 1265d4afb5ceSopenharmony_ci if ((lextable_h1[pos] & 0x7f) != c) { 1266d4afb5ceSopenharmony_cinope: 1267d4afb5ceSopenharmony_ci ah->lextable_pos = -1; 1268d4afb5ceSopenharmony_ci break; 1269d4afb5ceSopenharmony_ci } 1270d4afb5ceSopenharmony_ci /* fall thru */ 1271d4afb5ceSopenharmony_ci pos++; 1272d4afb5ceSopenharmony_ci if (lextable_h1[pos] == FAIL_CHAR) 1273d4afb5ceSopenharmony_ci goto nope; 1274d4afb5ceSopenharmony_ci 1275d4afb5ceSopenharmony_ci ah->lextable_pos = (int16_t)pos; 1276d4afb5ceSopenharmony_ci break; 1277d4afb5ceSopenharmony_ci } 1278d4afb5ceSopenharmony_ci 1279d4afb5ceSopenharmony_ci if (lextable_h1[pos] == FAIL_CHAR) 1280d4afb5ceSopenharmony_ci goto nope; 1281d4afb5ceSopenharmony_ci 1282d4afb5ceSopenharmony_ci /* b7 = 0, end or 3-byte */ 1283d4afb5ceSopenharmony_ci if (lextable_h1[pos] < FAIL_CHAR) { 1284d4afb5ceSopenharmony_ci if (!wsi->mux_substream) { 1285d4afb5ceSopenharmony_ci /* 1286d4afb5ceSopenharmony_ci * We hit a terminal marker, so 1287d4afb5ceSopenharmony_ci * we recognized this header... 1288d4afb5ceSopenharmony_ci * drop the speculative name 1289d4afb5ceSopenharmony_ci * part storage 1290d4afb5ceSopenharmony_ci */ 1291d4afb5ceSopenharmony_ci ah->pos = ah->unk_pos; 1292d4afb5ceSopenharmony_ci ah->unk_pos = 0; 1293d4afb5ceSopenharmony_ci } 1294d4afb5ceSopenharmony_ci 1295d4afb5ceSopenharmony_ci ah->lextable_pos = (int16_t)pos; 1296d4afb5ceSopenharmony_ci break; 1297d4afb5ceSopenharmony_ci } 1298d4afb5ceSopenharmony_ci 1299d4afb5ceSopenharmony_ci if (lextable_h1[pos] == c) { /* goto */ 1300d4afb5ceSopenharmony_ci ah->lextable_pos = (int16_t)(pos + 1301d4afb5ceSopenharmony_ci (lextable_h1[pos + 1]) + 1302d4afb5ceSopenharmony_ci (lextable_h1[pos + 2] << 8)); 1303d4afb5ceSopenharmony_ci break; 1304d4afb5ceSopenharmony_ci } 1305d4afb5ceSopenharmony_ci 1306d4afb5ceSopenharmony_ci /* fall thru goto */ 1307d4afb5ceSopenharmony_ci pos += 3; 1308d4afb5ceSopenharmony_ci /* continue */ 1309d4afb5ceSopenharmony_ci } 1310d4afb5ceSopenharmony_ci 1311d4afb5ceSopenharmony_ci /* 1312d4afb5ceSopenharmony_ci * If it's h1, server needs to be on the look out for 1313d4afb5ceSopenharmony_ci * unknown methods... 1314d4afb5ceSopenharmony_ci */ 1315d4afb5ceSopenharmony_ci if (ah->lextable_pos < 0 && lwsi_role_h1(wsi) && 1316d4afb5ceSopenharmony_ci lwsi_role_server(wsi)) { 1317d4afb5ceSopenharmony_ci /* 1318d4afb5ceSopenharmony_ci * this is not a header we know about... did 1319d4afb5ceSopenharmony_ci * we get a valid method (GET, POST etc) 1320d4afb5ceSopenharmony_ci * already, or is this the bogus method? 1321d4afb5ceSopenharmony_ci */ 1322d4afb5ceSopenharmony_ci for (m = 0; m < LWS_ARRAY_SIZE(methods); m++) 1323d4afb5ceSopenharmony_ci if (ah->frag_index[methods[m]]) { 1324d4afb5ceSopenharmony_ci /* 1325d4afb5ceSopenharmony_ci * already had the method 1326d4afb5ceSopenharmony_ci */ 1327d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_CUSTOM_HEADERS) 1328d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_SKIPPING; 1329d4afb5ceSopenharmony_ci#endif 1330d4afb5ceSopenharmony_ci if (wsi->mux_substream) 1331d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_SKIPPING; 1332d4afb5ceSopenharmony_ci break; 1333d4afb5ceSopenharmony_ci } 1334d4afb5ceSopenharmony_ci 1335d4afb5ceSopenharmony_ci if (m != LWS_ARRAY_SIZE(methods)) { 1336d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 1337d4afb5ceSopenharmony_ci /* 1338d4afb5ceSopenharmony_ci * We have the method, this is just an 1339d4afb5ceSopenharmony_ci * unknown header then 1340d4afb5ceSopenharmony_ci */ 1341d4afb5ceSopenharmony_ci if (!wsi->mux_substream) 1342d4afb5ceSopenharmony_ci goto unknown_hdr; 1343d4afb5ceSopenharmony_ci else 1344d4afb5ceSopenharmony_ci break; 1345d4afb5ceSopenharmony_ci#else 1346d4afb5ceSopenharmony_ci break; 1347d4afb5ceSopenharmony_ci#endif 1348d4afb5ceSopenharmony_ci } 1349d4afb5ceSopenharmony_ci /* 1350d4afb5ceSopenharmony_ci * ...it's an unknown http method from a client 1351d4afb5ceSopenharmony_ci * in fact, it cannot be valid http. 1352d4afb5ceSopenharmony_ci * 1353d4afb5ceSopenharmony_ci * Are we set up to transition to another role 1354d4afb5ceSopenharmony_ci * in these cases? 1355d4afb5ceSopenharmony_ci */ 1356d4afb5ceSopenharmony_ci if (lws_check_opt(wsi->a.vhost->options, 1357d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG)) { 1358d4afb5ceSopenharmony_ci lwsl_notice("%s: http fail fallback\n", 1359d4afb5ceSopenharmony_ci __func__); 1360d4afb5ceSopenharmony_ci /* transition to other role */ 1361d4afb5ceSopenharmony_ci return LPR_DO_FALLBACK; 1362d4afb5ceSopenharmony_ci } 1363d4afb5ceSopenharmony_ci 1364d4afb5ceSopenharmony_ci lwsl_info("Unknown method - dropping\n"); 1365d4afb5ceSopenharmony_ci goto forbid; 1366d4afb5ceSopenharmony_ci } 1367d4afb5ceSopenharmony_ci if (ah->lextable_pos < 0) { 1368d4afb5ceSopenharmony_ci /* 1369d4afb5ceSopenharmony_ci * It's not a header that lws knows about... 1370d4afb5ceSopenharmony_ci */ 1371d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 1372d4afb5ceSopenharmony_ci if (!wsi->mux_substream) 1373d4afb5ceSopenharmony_ci goto unknown_hdr; 1374d4afb5ceSopenharmony_ci#endif 1375d4afb5ceSopenharmony_ci /* 1376d4afb5ceSopenharmony_ci * ...otherwise for a client, let him ignore 1377d4afb5ceSopenharmony_ci * unknown headers coming from the server 1378d4afb5ceSopenharmony_ci */ 1379d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_SKIPPING; 1380d4afb5ceSopenharmony_ci break; 1381d4afb5ceSopenharmony_ci } 1382d4afb5ceSopenharmony_ci 1383d4afb5ceSopenharmony_ci if (lextable_h1[ah->lextable_pos] < FAIL_CHAR) { 1384d4afb5ceSopenharmony_ci /* terminal state */ 1385d4afb5ceSopenharmony_ci 1386d4afb5ceSopenharmony_ci n = ((unsigned int)lextable_h1[ah->lextable_pos] << 8) | 1387d4afb5ceSopenharmony_ci lextable_h1[ah->lextable_pos + 1]; 1388d4afb5ceSopenharmony_ci 1389d4afb5ceSopenharmony_ci lwsl_parser("known hdr %d\n", n); 1390d4afb5ceSopenharmony_ci for (m = 0; m < LWS_ARRAY_SIZE(methods); m++) 1391d4afb5ceSopenharmony_ci if (n == methods[m] && 1392d4afb5ceSopenharmony_ci ah->frag_index[methods[m]]) { 1393d4afb5ceSopenharmony_ci lwsl_warn("Duplicated method\n"); 1394d4afb5ceSopenharmony_ci return LPR_FAIL; 1395d4afb5ceSopenharmony_ci } 1396d4afb5ceSopenharmony_ci 1397d4afb5ceSopenharmony_ci if (!wsi->mux_substream) { 1398d4afb5ceSopenharmony_ci /* 1399d4afb5ceSopenharmony_ci * Whether we are collecting unknown names or not, 1400d4afb5ceSopenharmony_ci * if we matched an internal header we can dispense 1401d4afb5ceSopenharmony_ci * with the header name part we were keeping 1402d4afb5ceSopenharmony_ci */ 1403d4afb5ceSopenharmony_ci ah->pos = ah->unk_pos; 1404d4afb5ceSopenharmony_ci ah->unk_pos = 0; 1405d4afb5ceSopenharmony_ci } 1406d4afb5ceSopenharmony_ci 1407d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) 1408d4afb5ceSopenharmony_ci /* 1409d4afb5ceSopenharmony_ci * WSORIGIN is protocol equiv to ORIGIN, 1410d4afb5ceSopenharmony_ci * JWebSocket likes to send it, map to ORIGIN 1411d4afb5ceSopenharmony_ci */ 1412d4afb5ceSopenharmony_ci if (n == WSI_TOKEN_SWORIGIN) 1413d4afb5ceSopenharmony_ci n = WSI_TOKEN_ORIGIN; 1414d4afb5ceSopenharmony_ci#endif 1415d4afb5ceSopenharmony_ci 1416d4afb5ceSopenharmony_ci ah->parser_state = (uint8_t) 1417d4afb5ceSopenharmony_ci (WSI_TOKEN_GET_URI + n); 1418d4afb5ceSopenharmony_ci ah->ups = URIPS_IDLE; 1419d4afb5ceSopenharmony_ci 1420d4afb5ceSopenharmony_ci if (context->token_limits) 1421d4afb5ceSopenharmony_ci ah->current_token_limit = context-> 1422d4afb5ceSopenharmony_ci token_limits->token_limit[ 1423d4afb5ceSopenharmony_ci ah->parser_state]; 1424d4afb5ceSopenharmony_ci else 1425d4afb5ceSopenharmony_ci ah->current_token_limit = 1426d4afb5ceSopenharmony_ci wsi->a.context->max_http_header_data; 1427d4afb5ceSopenharmony_ci 1428d4afb5ceSopenharmony_ci if (ah->parser_state == WSI_TOKEN_CHALLENGE) 1429d4afb5ceSopenharmony_ci goto set_parsing_complete; 1430d4afb5ceSopenharmony_ci 1431d4afb5ceSopenharmony_ci goto start_fragment; 1432d4afb5ceSopenharmony_ci } 1433d4afb5ceSopenharmony_ci break; 1434d4afb5ceSopenharmony_ci 1435d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CUSTOM_HEADERS) 1436d4afb5ceSopenharmony_ciunknown_hdr: 1437d4afb5ceSopenharmony_ci //ah->parser_state = WSI_TOKEN_SKIPPING; 1438d4afb5ceSopenharmony_ci //break; 1439d4afb5ceSopenharmony_ci if (!wsi->mux_substream) 1440d4afb5ceSopenharmony_ci break; 1441d4afb5ceSopenharmony_ci#endif 1442d4afb5ceSopenharmony_ci 1443d4afb5ceSopenharmony_cistart_fragment: 1444d4afb5ceSopenharmony_ci ah->nfrag++; 1445d4afb5ceSopenharmony_ciexcessive: 1446d4afb5ceSopenharmony_ci if (ah->nfrag == LWS_ARRAY_SIZE(ah->frags)) { 1447d4afb5ceSopenharmony_ci lwsl_warn("More hdr frags than we can deal with\n"); 1448d4afb5ceSopenharmony_ci return LPR_FAIL; 1449d4afb5ceSopenharmony_ci } 1450d4afb5ceSopenharmony_ci 1451d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].offset = ah->pos; 1452d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].len = 0; 1453d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].nfrag = 0; 1454d4afb5ceSopenharmony_ci ah->frags[ah->nfrag].flags = 2; 1455d4afb5ceSopenharmony_ci 1456d4afb5ceSopenharmony_ci n = ah->frag_index[ah->parser_state]; 1457d4afb5ceSopenharmony_ci if (!n) { /* first fragment */ 1458d4afb5ceSopenharmony_ci ah->frag_index[ah->parser_state] = ah->nfrag; 1459d4afb5ceSopenharmony_ci ah->hdr_token_idx = ah->parser_state; 1460d4afb5ceSopenharmony_ci break; 1461d4afb5ceSopenharmony_ci } 1462d4afb5ceSopenharmony_ci /* continuation */ 1463d4afb5ceSopenharmony_ci while (ah->frags[n].nfrag) 1464d4afb5ceSopenharmony_ci n = ah->frags[n].nfrag; 1465d4afb5ceSopenharmony_ci ah->frags[n].nfrag = ah->nfrag; 1466d4afb5ceSopenharmony_ci 1467d4afb5ceSopenharmony_ci if (issue_char(wsi, ' ') < 0) 1468d4afb5ceSopenharmony_ci return LPR_FAIL; 1469d4afb5ceSopenharmony_ci break; 1470d4afb5ceSopenharmony_ci 1471d4afb5ceSopenharmony_ci /* skipping arg part of a name we didn't recognize */ 1472d4afb5ceSopenharmony_ci case WSI_TOKEN_SKIPPING: 1473d4afb5ceSopenharmony_ci lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c); 1474d4afb5ceSopenharmony_ci 1475d4afb5ceSopenharmony_ci if (c == '\x0a') { 1476d4afb5ceSopenharmony_ci /* broken peer */ 1477d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_NAME_PART; 1478d4afb5ceSopenharmony_ci ah->unk_pos = 0; 1479d4afb5ceSopenharmony_ci ah->lextable_pos = 0; 1480d4afb5ceSopenharmony_ci } 1481d4afb5ceSopenharmony_ci 1482d4afb5ceSopenharmony_ci if (c == '\x0d') 1483d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR; 1484d4afb5ceSopenharmony_ci break; 1485d4afb5ceSopenharmony_ci 1486d4afb5ceSopenharmony_ci case WSI_TOKEN_SKIPPING_SAW_CR: 1487d4afb5ceSopenharmony_ci lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c); 1488d4afb5ceSopenharmony_ci if (ah->ues != URIES_IDLE) 1489d4afb5ceSopenharmony_ci goto forbid; 1490d4afb5ceSopenharmony_ci if (c == '\x0a') { 1491d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_NAME_PART; 1492d4afb5ceSopenharmony_ci ah->unk_pos = 0; 1493d4afb5ceSopenharmony_ci ah->lextable_pos = 0; 1494d4afb5ceSopenharmony_ci } else 1495d4afb5ceSopenharmony_ci ah->parser_state = WSI_TOKEN_SKIPPING; 1496d4afb5ceSopenharmony_ci break; 1497d4afb5ceSopenharmony_ci /* we're done, ignore anything else */ 1498d4afb5ceSopenharmony_ci 1499d4afb5ceSopenharmony_ci case WSI_PARSING_COMPLETE: 1500d4afb5ceSopenharmony_ci lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c); 1501d4afb5ceSopenharmony_ci break; 1502d4afb5ceSopenharmony_ci } 1503d4afb5ceSopenharmony_ci 1504d4afb5ceSopenharmony_ci } while (*len); 1505d4afb5ceSopenharmony_ci 1506d4afb5ceSopenharmony_ci return LPR_OK; 1507d4afb5ceSopenharmony_ci 1508d4afb5ceSopenharmony_ciset_parsing_complete: 1509d4afb5ceSopenharmony_ci if (ah->ues != URIES_IDLE) 1510d4afb5ceSopenharmony_ci goto forbid; 1511d4afb5ceSopenharmony_ci 1512d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) { 1513d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) 1514d4afb5ceSopenharmony_ci const char *pv = lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION); 1515d4afb5ceSopenharmony_ci if (pv) 1516d4afb5ceSopenharmony_ci wsi->rx_frame_type = (char)atoi(pv); 1517d4afb5ceSopenharmony_ci 1518d4afb5ceSopenharmony_ci lwsl_parser("v%02d hdrs done\n", wsi->rx_frame_type); 1519d4afb5ceSopenharmony_ci#endif 1520d4afb5ceSopenharmony_ci } 1521d4afb5ceSopenharmony_ci ah->parser_state = WSI_PARSING_COMPLETE; 1522d4afb5ceSopenharmony_ci wsi->hdr_parsing_completed = 1; 1523d4afb5ceSopenharmony_ci 1524d4afb5ceSopenharmony_ci return LPR_OK; 1525d4afb5ceSopenharmony_ci 1526d4afb5ceSopenharmony_ciforbid: 1527d4afb5ceSopenharmony_ci lwsl_info(" forbidding on uri sanitation\n"); 1528d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 1529d4afb5ceSopenharmony_ci lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL); 1530d4afb5ceSopenharmony_ci#endif 1531d4afb5ceSopenharmony_ci 1532d4afb5ceSopenharmony_ci return LPR_FORBIDDEN; 1533d4afb5ceSopenharmony_ci} 1534d4afb5ceSopenharmony_ci 1535d4afb5ceSopenharmony_ciint 1536d4afb5ceSopenharmony_cilws_http_cookie_get(struct lws *wsi, const char *name, char *buf, 1537d4afb5ceSopenharmony_ci size_t *max_len) 1538d4afb5ceSopenharmony_ci{ 1539d4afb5ceSopenharmony_ci size_t max = *max_len, bl = strlen(name); 1540d4afb5ceSopenharmony_ci char *p, *bo = buf; 1541d4afb5ceSopenharmony_ci int n; 1542d4afb5ceSopenharmony_ci 1543d4afb5ceSopenharmony_ci n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE); 1544d4afb5ceSopenharmony_ci if ((unsigned int)n < bl + 1) 1545d4afb5ceSopenharmony_ci return 1; 1546d4afb5ceSopenharmony_ci 1547d4afb5ceSopenharmony_ci /* 1548d4afb5ceSopenharmony_ci * This can come to us two ways, in ah fragments (h2) or as a single 1549d4afb5ceSopenharmony_ci * semicolon-delimited string (h1) 1550d4afb5ceSopenharmony_ci */ 1551d4afb5ceSopenharmony_ci 1552d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 1553d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_METHOD)) { 1554d4afb5ceSopenharmony_ci 1555d4afb5ceSopenharmony_ci /* 1556d4afb5ceSopenharmony_ci * The h2 way... 1557d4afb5ceSopenharmony_ci */ 1558d4afb5ceSopenharmony_ci 1559d4afb5ceSopenharmony_ci int f = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_COOKIE]; 1560d4afb5ceSopenharmony_ci size_t fl; 1561d4afb5ceSopenharmony_ci 1562d4afb5ceSopenharmony_ci while (f) { 1563d4afb5ceSopenharmony_ci p = wsi->http.ah->data + wsi->http.ah->frags[f].offset; 1564d4afb5ceSopenharmony_ci fl = (size_t)wsi->http.ah->frags[f].len; 1565d4afb5ceSopenharmony_ci if (fl >= bl + 1 && 1566d4afb5ceSopenharmony_ci p[bl] == '=' && 1567d4afb5ceSopenharmony_ci !memcmp(p, name, bl)) { 1568d4afb5ceSopenharmony_ci fl -= bl + 1; 1569d4afb5ceSopenharmony_ci if (max - 1 < fl) 1570d4afb5ceSopenharmony_ci fl = max - 1; 1571d4afb5ceSopenharmony_ci if (fl) 1572d4afb5ceSopenharmony_ci memcpy(buf, p + bl + 1, fl); 1573d4afb5ceSopenharmony_ci *max_len = fl; 1574d4afb5ceSopenharmony_ci buf[fl] = '\0'; 1575d4afb5ceSopenharmony_ci 1576d4afb5ceSopenharmony_ci return 0; 1577d4afb5ceSopenharmony_ci } 1578d4afb5ceSopenharmony_ci f = wsi->http.ah->frags[f].nfrag; 1579d4afb5ceSopenharmony_ci } 1580d4afb5ceSopenharmony_ci 1581d4afb5ceSopenharmony_ci return -1; 1582d4afb5ceSopenharmony_ci } 1583d4afb5ceSopenharmony_ci#endif 1584d4afb5ceSopenharmony_ci 1585d4afb5ceSopenharmony_ci /* 1586d4afb5ceSopenharmony_ci * The h1 way... 1587d4afb5ceSopenharmony_ci */ 1588d4afb5ceSopenharmony_ci 1589d4afb5ceSopenharmony_ci p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE); 1590d4afb5ceSopenharmony_ci if (!p) 1591d4afb5ceSopenharmony_ci return 1; 1592d4afb5ceSopenharmony_ci 1593d4afb5ceSopenharmony_ci p += bl; 1594d4afb5ceSopenharmony_ci n -= (int)bl; 1595d4afb5ceSopenharmony_ci while (n-- > 0) { 1596d4afb5ceSopenharmony_ci if (*p == '=' && !memcmp(p - bl, name, (unsigned int)bl)) { 1597d4afb5ceSopenharmony_ci p++; 1598d4afb5ceSopenharmony_ci while (*p != ';' && n-- && max) { 1599d4afb5ceSopenharmony_ci *buf++ = *p++; 1600d4afb5ceSopenharmony_ci max--; 1601d4afb5ceSopenharmony_ci } 1602d4afb5ceSopenharmony_ci if (!max) 1603d4afb5ceSopenharmony_ci return 2; 1604d4afb5ceSopenharmony_ci 1605d4afb5ceSopenharmony_ci *buf = '\0'; 1606d4afb5ceSopenharmony_ci *max_len = lws_ptr_diff_size_t(buf, bo); 1607d4afb5ceSopenharmony_ci 1608d4afb5ceSopenharmony_ci return 0; 1609d4afb5ceSopenharmony_ci } 1610d4afb5ceSopenharmony_ci p++; 1611d4afb5ceSopenharmony_ci } 1612d4afb5ceSopenharmony_ci 1613d4afb5ceSopenharmony_ci return 1; 1614d4afb5ceSopenharmony_ci} 1615d4afb5ceSopenharmony_ci 1616d4afb5ceSopenharmony_ci#if defined(LWS_WITH_JOSE) 1617d4afb5ceSopenharmony_ci 1618d4afb5ceSopenharmony_ci#define MAX_JWT_SIZE 1024 1619d4afb5ceSopenharmony_ci 1620d4afb5ceSopenharmony_ciint 1621d4afb5ceSopenharmony_cilws_jwt_get_http_cookie_validate_jwt(struct lws *wsi, 1622d4afb5ceSopenharmony_ci struct lws_jwt_sign_set_cookie *i, 1623d4afb5ceSopenharmony_ci char *out, size_t *out_len) 1624d4afb5ceSopenharmony_ci{ 1625d4afb5ceSopenharmony_ci char temp[MAX_JWT_SIZE * 2]; 1626d4afb5ceSopenharmony_ci size_t cml = *out_len; 1627d4afb5ceSopenharmony_ci const char *cp; 1628d4afb5ceSopenharmony_ci 1629d4afb5ceSopenharmony_ci /* first use out to hold the encoded JWT */ 1630d4afb5ceSopenharmony_ci 1631d4afb5ceSopenharmony_ci if (lws_http_cookie_get(wsi, i->cookie_name, out, out_len)) { 1632d4afb5ceSopenharmony_ci lwsl_debug("%s: cookie %s not provided\n", __func__, 1633d4afb5ceSopenharmony_ci i->cookie_name); 1634d4afb5ceSopenharmony_ci return 1; 1635d4afb5ceSopenharmony_ci } 1636d4afb5ceSopenharmony_ci 1637d4afb5ceSopenharmony_ci /* decode the JWT into temp */ 1638d4afb5ceSopenharmony_ci 1639d4afb5ceSopenharmony_ci if (lws_jwt_signed_validate(wsi->a.context, i->jwk, i->alg, out, 1640d4afb5ceSopenharmony_ci *out_len, temp, sizeof(temp), out, &cml)) { 1641d4afb5ceSopenharmony_ci lwsl_info("%s: jwt validation failed\n", __func__); 1642d4afb5ceSopenharmony_ci return 1; 1643d4afb5ceSopenharmony_ci } 1644d4afb5ceSopenharmony_ci 1645d4afb5ceSopenharmony_ci /* 1646d4afb5ceSopenharmony_ci * Copy out the decoded JWT payload into out, overwriting the 1647d4afb5ceSopenharmony_ci * original encoded JWT taken from the cookie (that has long ago been 1648d4afb5ceSopenharmony_ci * translated into allocated buffers in the JOSE object) 1649d4afb5ceSopenharmony_ci */ 1650d4afb5ceSopenharmony_ci 1651d4afb5ceSopenharmony_ci if (lws_jwt_token_sanity(out, cml, i->iss, i->aud, i->csrf_in, 1652d4afb5ceSopenharmony_ci i->sub, sizeof(i->sub), 1653d4afb5ceSopenharmony_ci &i->expiry_unix_time)) { 1654d4afb5ceSopenharmony_ci lwsl_notice("%s: jwt sanity failed\n", __func__); 1655d4afb5ceSopenharmony_ci return 1; 1656d4afb5ceSopenharmony_ci } 1657d4afb5ceSopenharmony_ci 1658d4afb5ceSopenharmony_ci /* 1659d4afb5ceSopenharmony_ci * If he's interested in his private JSON part, point him to that in 1660d4afb5ceSopenharmony_ci * the args struct (it's pointing to the data in out 1661d4afb5ceSopenharmony_ci */ 1662d4afb5ceSopenharmony_ci 1663d4afb5ceSopenharmony_ci cp = lws_json_simple_find(out, cml, "\"ext\":", &i->extra_json_len); 1664d4afb5ceSopenharmony_ci if (cp) 1665d4afb5ceSopenharmony_ci i->extra_json = cp; 1666d4afb5ceSopenharmony_ci 1667d4afb5ceSopenharmony_ci if (!cp) 1668d4afb5ceSopenharmony_ci lwsl_notice("%s: no ext JWT payload\n", __func__); 1669d4afb5ceSopenharmony_ci 1670d4afb5ceSopenharmony_ci return 0; 1671d4afb5ceSopenharmony_ci} 1672d4afb5ceSopenharmony_ci 1673d4afb5ceSopenharmony_ciint 1674d4afb5ceSopenharmony_cilws_jwt_sign_token_set_http_cookie(struct lws *wsi, 1675d4afb5ceSopenharmony_ci const struct lws_jwt_sign_set_cookie *i, 1676d4afb5ceSopenharmony_ci uint8_t **p, uint8_t *end) 1677d4afb5ceSopenharmony_ci{ 1678d4afb5ceSopenharmony_ci char plain[MAX_JWT_SIZE + 1], temp[MAX_JWT_SIZE * 2], csrf[17]; 1679d4afb5ceSopenharmony_ci size_t pl = sizeof(plain); 1680d4afb5ceSopenharmony_ci unsigned long long ull; 1681d4afb5ceSopenharmony_ci int n; 1682d4afb5ceSopenharmony_ci 1683d4afb5ceSopenharmony_ci /* 1684d4afb5ceSopenharmony_ci * Create a 16-char random csrf token with the same lifetime as the JWT 1685d4afb5ceSopenharmony_ci */ 1686d4afb5ceSopenharmony_ci 1687d4afb5ceSopenharmony_ci lws_hex_random(wsi->a.context, csrf, sizeof(csrf)); 1688d4afb5ceSopenharmony_ci ull = lws_now_secs(); 1689d4afb5ceSopenharmony_ci if (lws_jwt_sign_compact(wsi->a.context, i->jwk, i->alg, plain, &pl, 1690d4afb5ceSopenharmony_ci temp, sizeof(temp), 1691d4afb5ceSopenharmony_ci "{\"iss\":\"%s\",\"aud\":\"%s\"," 1692d4afb5ceSopenharmony_ci "\"iat\":%llu,\"nbf\":%llu,\"exp\":%llu," 1693d4afb5ceSopenharmony_ci "\"csrf\":\"%s\",\"sub\":\"%s\"%s%s%s}", 1694d4afb5ceSopenharmony_ci i->iss, i->aud, ull, ull - 60, 1695d4afb5ceSopenharmony_ci ull + i->expiry_unix_time, 1696d4afb5ceSopenharmony_ci csrf, i->sub, 1697d4afb5ceSopenharmony_ci i->extra_json ? ",\"ext\":{" : "", 1698d4afb5ceSopenharmony_ci i->extra_json ? i->extra_json : "", 1699d4afb5ceSopenharmony_ci i->extra_json ? "}" : "")) { 1700d4afb5ceSopenharmony_ci lwsl_err("%s: failed to create JWT\n", __func__); 1701d4afb5ceSopenharmony_ci 1702d4afb5ceSopenharmony_ci return 1; 1703d4afb5ceSopenharmony_ci } 1704d4afb5ceSopenharmony_ci 1705d4afb5ceSopenharmony_ci /* 1706d4afb5ceSopenharmony_ci * There's no point the browser holding on to a JWT beyond the JWT's 1707d4afb5ceSopenharmony_ci * expiry time, so set it to be the same. 1708d4afb5ceSopenharmony_ci */ 1709d4afb5ceSopenharmony_ci 1710d4afb5ceSopenharmony_ci n = lws_snprintf(temp, sizeof(temp), "__Host-%s=%s;" 1711d4afb5ceSopenharmony_ci "HttpOnly;" 1712d4afb5ceSopenharmony_ci "Secure;" 1713d4afb5ceSopenharmony_ci "SameSite=strict;" 1714d4afb5ceSopenharmony_ci "Path=/;" 1715d4afb5ceSopenharmony_ci "Max-Age=%lu", 1716d4afb5ceSopenharmony_ci i->cookie_name, plain, i->expiry_unix_time); 1717d4afb5ceSopenharmony_ci 1718d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SET_COOKIE, 1719d4afb5ceSopenharmony_ci (uint8_t *)temp, n, p, end)) { 1720d4afb5ceSopenharmony_ci lwsl_err("%s: failed to add JWT cookie header\n", __func__); 1721d4afb5ceSopenharmony_ci return 1; 1722d4afb5ceSopenharmony_ci } 1723d4afb5ceSopenharmony_ci 1724d4afb5ceSopenharmony_ci return 0; 1725d4afb5ceSopenharmony_ci} 1726d4afb5ceSopenharmony_ci#endif 1727