aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorThijs Schreijer <thijs@thijsschreijer.nl>2026-07-30 19:22:17 +0200
committerThijs Schreijer <thijs@thijsschreijer.nl>2026-07-30 22:06:04 +0200
commit73b0780321acb14bab6707006f5136ea9998951d (patch)
tree30c5d0cff89913185df7f5fb7ebe1636827cfd58 /docs
parente13de2013749961edaa126697f3290d3dca91823 (diff)
downloadluasocket-73b0780321acb14bab6707006f5136ea9998951d.tar.gz
luasocket-73b0780321acb14bab6707006f5136ea9998951d.tar.bz2
luasocket-73b0780321acb14bab6707006f5136ea9998951d.zip
feat(receive): add maxsize argument to bound memory usage
client:receive("*l") and receive("*a") are unbounded: a peer that never sends a newline, or never closes, makes LuaSocket buffer until the process runs out of memory (e.g. src/http.lua reading response headers in a loop). Add an optional maxsize argument that caps the payload a single call may accumulate, including prefix. - Hoist all argument validation ahead of timeout_markstart() so bad calls (maxsize < 1, #prefix >= maxsize, numeric pattern > maxsize) raise before any I/O and leave the socket untouched. - recvline/recvall take a budget and return a new internal BUF_OVERSIZED code, surfaced to Lua as the "oversized" error alongside "timeout"/"closed", with the partial held in the 3rd return value. - recvraw is left untouched: argument checks make the cap unreachable for numeric patterns. - Preserve three invariants: a timeout partial is always shorter than maxsize (safe to retry as prefix), completion beats the cap for *a, and no bytes are lost or skipped on overflow. - tcp.c, unixstream.c and serial.c all share this code path unchanged. Adds test coverage (argument errors, *l/*a boundaries, timeout/close at the cap, the drain idiom, numeric patterns, unix-stream mirror) and documents the new argument, error, and recovery idioms in docs/tcp.html.
Diffstat (limited to 'docs')
-rw-r--r--docs/tcp.html58
1 files changed, 55 insertions, 3 deletions
diff --git a/docs/tcp.html b/docs/tcp.html
index a26228d..4c6c6bc 100644
--- a/docs/tcp.html
+++ b/docs/tcp.html
@@ -351,7 +351,7 @@ method returns <b><tt>nil</tt></b> followed by an error message.
351<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 351<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
352 352
353<p class="name" id="receive"> 353<p class="name" id="receive">
354client:<b>receive(</b>[pattern [, prefix]]<b>)</b> 354client:<b>receive(</b>[pattern [, prefix [, maxsize]]]<b>)</b>
355</p> 355</p>
356 356
357<p class="description"> 357<p class="description">
@@ -380,14 +380,23 @@ of bytes from the socket.</li>
380of any received data before return. 380of any received data before return.
381</p> 381</p>
382 382
383<p class="parameters">
384<tt>Maxsize</tt> is an optional positive integer bounding the number of
385payload bytes the call may accumulate, <em>including</em> <tt>prefix</tt>.
386Omitted or <tt><b>nil</b></tt> means unlimited.
387</p>
388
383<p class="return"> 389<p class="return">
384If successful, the method returns the received pattern. In case of error, 390If successful, the method returns the received pattern. In case of error,
385the method returns <tt><b>nil</b></tt> followed by an error 391the method returns <tt><b>nil</b></tt> followed by an error
386message, followed by a (possibly empty) string containing 392message, followed by a (possibly empty) string containing
387the partial that was received. The error message can be 393the partial that was received. The error message can be
388the string '<tt>closed</tt>' in case the connection was 394the string '<tt>closed</tt>' in case the connection was
389closed before the transmission was completed or the string 395closed before the transmission was completed, the string
390'<tt>timeout</tt>' in case there was a timeout during the operation. 396'<tt>timeout</tt>' in case there was a timeout during the operation, or,
397when <tt>maxsize</tt> was given, the string '<tt>oversized</tt>' in case
398the pattern did not complete within <tt>maxsize</tt> bytes -- in which case
399the third return value holds exactly <tt>maxsize</tt> bytes.
391</p> 400</p>
392 401
393<p class="note"> 402<p class="note">
@@ -399,6 +408,49 @@ functions should return <tt><b>nil</b></tt> on error. Thus it was changed
399too. 408too.
400</p> 409</p>
401 410
411<p class="note">
412<b>Note on <tt>maxsize</tt></b>: passing a <tt>maxsize</tt> that is smaller
413than 1, a <tt>prefix</tt> whose length is greater than or equal to
414<tt>maxsize</tt>, or, for a numeric <tt>pattern</tt>, a byte count greater
415than <tt>maxsize</tt>, all raise a Lua error rather than returning
416<tt><b>nil</b></tt> plus a message -- these are caller logic errors, and
417they are detected before any byte is read from the socket. To drain and
418discard an oversized line while keeping memory bounded and the stream
419aligned:
420</p>
421
422<pre class="example">
423local data, err, part
424repeat
425 data, err, part = client:receive("*l", "", 4096)
426until err ~= "oversized"
427</pre>
428
429<p class="note">
430To instead retry and eventually get the whole thing, carry the partial
431forward as <tt>prefix</tt> and grow <tt>maxsize</tt>:
432</p>
433
434<pre class="example">
435local data, err, part = client:receive("*l", nil, 4096)
436if err == "oversized" then
437 data, err, part = client:receive("*l", part, 65536) -- larger cap, or this raises
438end
439</pre>
440
441<p class="note">
442Retrying with <tt>prefix</tt> set to the previous partial result and an
443<em>unchanged</em> <tt>maxsize</tt> raises the length-check error above by
444design -- otherwise it would be a zero-progress spin: no I/O, no timeout,
445no error, just CPU. A <tt>timeout</tt> partial is always strictly shorter
446than <tt>maxsize</tt>, so it is always safe to feed straight back as
447<tt>prefix</tt> with the same <tt>maxsize</tt>. Finally, note that
448<tt>maxsize</tt> bounds the payload <em>returned</em>, not necessarily the
449bytes taken off the wire: for the <tt>*l</tt> pattern the discarded CR
450characters and the line terminator mean more bytes may have been consumed
451than the returned length suggests.
452</p>
453
402<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 454<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
403 455
404<p class="name" id="send"> 456<p class="name" id="send">