Jens Geyer created THRIFT-6161:
----------------------------------

             Summary: Haxe TStreamTransport does not charge reads against 
MaxMessageSize
                 Key: THRIFT-6161
                 URL: https://issues.apache.org/jira/browse/THRIFT-6161
             Project: Thrift
          Issue Type: Bug
          Components: Haxe - Library
            Reporter: Jens Geyer
             Fix For: 0.25.0


h3. Problem

{{TStreamTransport}} does not charge reads against the message budget, so 
MaxMessageSize has
no effect on a stream-backed connection however much a message reads, as long 
as no single
read exceeds the limit on its own. Its {{flush()}} does not restore the 
allowance either.

h3. Why this is a defect in Haxe specifically

There is no single convention across the bindings — there are three, and every 
other binding
keeps to one of them:

* *cpp, c_glib* — no endpoint charges reads (only the zlib transport does); 
reads are bounded by frame binding and the per-read check alone.
* *java, netstd* — stream and socket endpoints do not charge; endpoints that 
know the message boundary do ({{THttpClient}} / {{THttpTransport}}, named 
pipes, a memory buffer holding one message).
* *delphi* — every endpoint charges.

Haxe is the only binding that departs from its own convention. It has four 
endpoint transports:
{{TSocket}} charges (three sites), {{THttpClient}} charges, 
{{TFullDuplexHttpClient}} charges,
and {{TStreamTransport}} charges nothing. The binding's design intends 
endpoints to charge, and
this one silently opts out.

{{doc/specs/thrift-tconfiguration.md}} describes MaxMessageSize as "a general 
device to be used
with any transport or protocol", expressed as the bytes *remaining* to be read 
— which only
means something if reads draw it down.

h3. Fix

Two coordinated changes, mirroring {{TSocket}}:

* {{read()}} charges what it read.
* {{flush()}} resets the allowance, at the same point {{TSocket}} does.

Both are needed. Charging without resetting would leave the budget only ever 
shrinking, so a
long-lived connection would run itself out of it — which is THRIFT-6160, fixed 
just before this.

h3. Tests

Two, in {{StreamTest}}, failing before and passing after. The first reads past 
the limit 32 bytes
at a time, so nothing but cumulative accounting can catch it; the second checks 
the allowance comes
back. Verified on neko (full suite, including the existing stream, constants 
and recursion-limit
tests, all of which read through {{TStreamTransport}}); the python and php 
targets cross-compile
clean.

_Drafted with AI assistance (Claude Opus 5); reviewed and filed by Jens Geyer._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to