@@ -338,3 +338,127 @@ lws_flow_req(lws_flow_t *flow)
338338 flow -> state != LWSDLOFLOW_STATE_READ ? LWS_SRET_OK :
339339 LWS_SRET_WANT_INPUT ;
340340}
341+
342+
343+ static void
344+ lws_wsmsg_transfer (lws_wsmsg_info_t * info )
345+ {
346+ struct lws_buflist * bl = info -> private_heads [info -> private_source_idx ],
347+ * ubl = * info -> head_upstream ;
348+
349+ /*
350+ * If we arrived at a complete message, and the upstream is
351+ * not blocked awaiting EOM, transfer the segments to the
352+ * upstream, emptying the private buflist
353+ */
354+
355+ if (!bl ) {
356+ lwsl_notice ("%s: denied: no content to transfer\n" , __func__ );
357+ return ;
358+ }
359+
360+ while (bl && bl -> next )
361+ bl = bl -> next ;
362+
363+ if (bl -> awaiting_eom ) {
364+ lwsl_notice ("%s: denied: head awaiting EOM\n" , __func__ );
365+ return ;
366+ }
367+
368+ if (!* info -> head_upstream ) {
369+ /*
370+ * If the upstream is empty, create it by pointing
371+ * it to the whole private chain, taking ownership
372+ */
373+
374+ * info -> head_upstream = info -> private_heads [info -> private_source_idx ];
375+ info -> private_heads [info -> private_source_idx ] = NULL ;
376+
377+ lwsl_notice ("%s: transferred: head -> head_upstream\n" , __func__ );
378+
379+ return ;
380+ }
381+
382+
383+ /* find the end of the existing upstream */
384+
385+ while (ubl && ubl -> next )
386+ ubl = ubl -> next ;
387+
388+ if (ubl -> awaiting_eom ) {
389+ lwsl_notice ("%s: denied: no content to transfer\n" , __func__ );
390+ return ;
391+ }
392+
393+ /*
394+ * Add the private buflist on to the end of
395+ * the upstream buflist, taking ownership
396+ */
397+
398+ ubl -> next = info -> private_heads [info -> private_source_idx ];
399+ info -> private_heads [info -> private_source_idx ] = NULL ; /* now it transferred upstream, private owns nothing */
400+ }
401+
402+ int
403+ lws_wsmsg_append (lws_wsmsg_info_t * info )
404+ {
405+ struct lws_buflist * bl ;
406+
407+ /*
408+ * if there's nothing already stored, the new message is complete,
409+ * and the upstream is either empty, or is not blocked awaiting EOM,
410+ * then just apply the message directly to the upstream.
411+ */
412+
413+ if (!info -> private_heads [info -> private_source_idx ] &&
414+ (info -> ss_flags == (LWSSS_FLAG_SOM | LWSSS_FLAG_EOM )) &&
415+ (!(* info -> head_upstream ) || !(* info -> head_upstream )-> awaiting_eom )) {
416+
417+ lwsl_notice ("%s: directly applying upstream\n" , __func__ );
418+
419+ if (lws_buflist_append_segment (info -> head_upstream , info -> buf , info -> len ) < 0 )
420+ return -1 ;
421+
422+ /*
423+ * Let's tag the tail buflist we just added,
424+ * with extra information useful for debugging
425+ */
426+
427+ bl = * info -> head_upstream ;
428+ } else {
429+ /*
430+ * Otherwise, apply the message to the private buflist first
431+ */
432+
433+ lwsl_notice ("%s: applying via private buflist\n" , __func__ );
434+
435+ if (lws_buflist_append_segment (& info -> private_heads [info -> private_source_idx ],
436+ info -> buf , info -> len ) < 0 )
437+ return -1 ;
438+
439+ bl = info -> private_heads [info -> private_source_idx ];
440+ }
441+
442+ while (bl && bl -> next )
443+ bl = bl -> next ;
444+
445+ if (!bl )
446+ return 0 ;
447+
448+ bl -> awaiting_eom = !(info -> ss_flags & LWSSS_FLAG_EOM );
449+ bl -> src_channel = (unsigned char )info -> private_source_idx ;
450+
451+ lws_wsmsg_transfer (info );
452+
453+ return 0 ;
454+ }
455+
456+ void
457+ lws_wsmsg_destroy (struct lws_buflist * private_heads [], size_t count_private_heads )
458+ {
459+ size_t m = 0 ;
460+
461+ while (m < count_private_heads )
462+ lws_buflist_destroy_all_segments (& private_heads [m ++ ]);
463+ }
464+
0 commit comments