@@ -43,23 +43,51 @@ struct HttpResponseData : AsyncSocketData<SSL>, HttpParser {
4343 state &= ~HttpResponseData<SSL >::HTTP_RESPONSE_PENDING ;
4444 }
4545
46- /* Caller of onWritable. It is possible onWritable calls markDone so we need to borrow it. */
46+ /* Caller of onWritable. It is possible onWritable calls markDone so we need to borrow it.
47+ * It is also possible user code sets a new onWritable while running user registered onWritable. */
4748 bool callOnWritable (uintmax_t offset) {
48- /* Borrow real onWritable */
49+ /* 1. Borrow the real callback */
4950 MoveOnlyFunction<bool (uintmax_t )> borrowedOnWritable = std::move (onWritable);
50-
51- /* Set onWritable to placeholder */
52- onWritable = [](uintmax_t ) {return true ;};
53-
54- /* Run borrowed onWritable */
51+
52+ /* 2. Setup the stack-based detection flag */
53+ bool placeholderReplaced = false ;
54+
55+ struct Sentinel {
56+ bool *replacedFlag;
57+ Sentinel (bool *f) : replacedFlag(f) {}
58+
59+ Sentinel (Sentinel &&other) noexcept : replacedFlag(other.replacedFlag) {
60+ other.replacedFlag = nullptr ;
61+ }
62+
63+ ~Sentinel () {
64+ if (replacedFlag) {
65+ *replacedFlag = true ;
66+ }
67+ }
68+
69+ /* Delete copy to ensure move-only semantics */
70+ Sentinel (const Sentinel&) = delete ;
71+ Sentinel& operator =(const Sentinel&) = delete ;
72+ };
73+
74+ /* 3. Set placeholder with the captured Sentinel */
75+ onWritable = [tracker = Sentinel (&placeholderReplaced)](uintmax_t ) {
76+ return true ;
77+ };
78+
79+ /* 4. Run the borrowed callback */
5580 bool ret = borrowedOnWritable (offset);
56-
57- /* If we still have onWritable (the placeholder) then move back the real one */
58- if (onWritable) {
59- /* We haven't reset onWritable, so give it back */
81+
82+ /*
83+ 5. If placeholderReplaced is STILL false, it means the lambda (and its Sentinel)
84+ is still sitting inside 'onWritable'. If it's true, the lambda was destroyed
85+ to make room for a new one.
86+ */
87+ if (!placeholderReplaced) {
6088 onWritable = std::move (borrowedOnWritable);
6189 }
62-
90+
6391 return ret;
6492 }
6593private:
0 commit comments