726 Commits
Author SHA1 Message Date
Jens GeyerandClaude Opus 5.5 45d7648557 Keep the HttpClient's default request config in THttpClient
Client: java

Requests now go out with the default request config of the HttpClient
passed in; a connect timeout set on the transport is added on top of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 01:23:02 +01:00
Zibran Khan bd3ba6f128 THRIFT-4408: Decode JSON \u escapes above \u7fff in Java TJSONProtocol
Client: java

readJSONString assembled the four hex digits of a \uXXXX escape into a
short, so escapes from \u8000 to \uffff became negative code units. The
surrogate branches cast the value back to char, but the plain-character
branch passed it to new String(int[]) and the read ended in an
IllegalArgumentException. Keep the code unit as a char.

An unpaired high surrogate escape was also accepted silently when the
string ended or when a plain character or a non-surrogate escape
followed it, in the last case emitting the characters out of order.
Reject it with INVALID_DATA, as the C++ reader does.
2026-10-28 01:10:01 +01:00
Dmytro ShteflyukandOpenAI Codex f47092e700 Fix PHPStan and Java Spotless failures (#4032)
Client: java,php

Co-authored-by: OpenAI Codex (gpt-6.1-sol) <codex@openai.com>
2026-10-20 22:04:58 -04:00
Jens GeyerandClaude Opus 4.8 689a9c2beb Check the declared length before skipping a string or binary field
Client: java

TBinaryProtocol and TCompactProtocol now apply the same length check on the
skip path that readString and readBinary use, so the declared size is
validated before any bytes are consumed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-20 23:52:59 +02:00
Jens GeyerandClaude Opus 4.8 d1ee84c3be Close a failed connection before logging and keep the network thread alive
Client: java

The nonblocking SASL server now closes the failing connection before it logs,
and routes the logging through a call that cannot end the network thread, so
handling one connection's failure leaves the others served.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-20 23:48:24 +02:00
Sylwester LachiewiczandClaude Opus 5.5 c8151cd32f THRIFT-6080: Stop copying a binary field on every call to its byte[] getter
Client: java

The generated byte[] getX() right-sized the field and stored it through setX(),
which copies again with copyBinary, so every call copied the bytes although it
returns the field's own array either way. It now assigns the right-sized buffer
directly, as Apache Accumulo already does by patching the generated code.
Union getters and bufferForX() are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:48:32 +02:00
dependabot[bot] f61566e177 Bump com.diffplug.spotless from 8.10.0 to 8.10.2 in /lib/kotlin
Bumps com.diffplug.spotless from 8.10.0 to 8.10.2.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-01 23:41:47 +02:00
Jens GeyerandClaude Opus 5 299a678f43 Keep the SASL nonblocking server serving when one connection fails
Client: java

A failure while a network thread handles one connection now closes only
that connection. If a network thread ends anyway, the server stops, as it
already does when the acceptor thread ends.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 02:01:10 +02:00
Jens GeyerandClaude Opus 5 6e992c1d1b Stop reading a deferred frame until read buffer memory is released
Client: java

The nonblocking servers now clear the read interest of a connection whose
frame does not fit into the read buffer memory limit and restore it once
memory is released. A frame larger than that limit closes its connection,
as a frame over the maximum frame size does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 01:55:05 +02:00
Jens GeyerandClaude Opus 4.8 4af34984f8 Close a SASL connection whose response evaluation fails unexpectedly
Client: java

When evaluating a client's SASL response throws an unexpected runtime
exception, transition the connection to its closing phase so the network
thread closes it, matching how the processing phase already handles such
failures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-22 01:49:28 +02:00
Sylwester LachiewiczandClaude Opus 5 6674b51268 THRIFT-6275: Present the client certificate from the Go cross-test client
Client: go,test

The Go test client sent no client certificate, so every socket transport
over SSL failed the handshake against the Python server, which requires
one. It now takes the server's --certPath flag and loads client_v3.

Go 1.27 and later refuse to load client_v3.crt as shipped: its
alternative names include ::ffff:127.0.0.1, and the x509 parser rejects
an IPv4-mapped IPv6 SAN since go1.27.0. The lib-go job runs on 1.27 and
test/go now loads the certificate, so it is regenerated without that
entry. THRIFT-3660 added it for the Python peer-address check, which
since THRIFT-6201 reduces a mapped address itself. The new certificate
is self-signed with the same key, distinguished name and extensions, as
the shipped one was. The Java client keystore is regenerated from it,
and the README recipe now produces what is shipped instead of a
CA-signed certificate the Python server does not trust.

The 18 py-go SSL entries leave the known failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 09:56:00 -07:00
Jens Geyer 451efc7a72 bump master version 2026-09-18 09:00:54 +02:00
Jens GeyerandClaude Opus 4.8 1311cf3619 Cap the capacity reserved for a container's declared element count
Generated Java decoders sized a list, set or map from the element count in the
container header before reading any element, so a peer could name a count it
never backs with data and have the decoder reserve capacity for all of it. The
same holds for the functional read API in TProtocol (readList/readSet/readMap
with the default collection creators), which sized the collection from the wire
count too.

TBaseHelper.preallocSize caps that initial reservation at 1024 elements and
treats a negative count -- including a hash container's doubled count overflowing
int -- as zero. The generated decoders and the default creators now route the
count through it. Containers larger than the cap grow as elements are added,
exactly as counts under the cap already did. This mirrors thrift.PreallocSize in
the Go binding and prealloc_size in Rust.

Client: java

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-16 01:55:19 +02:00
Jens GeyerandClaude Opus 5 715f46c2ed Use the client certificate with subjectAltNames in the SSL cross-test clients
Client: cpp,java,kotlin,nodejs,py,rb,rs

The SSL cross tests against a Python server have failed since the server side
validation callback became a real check on Python 3.12 and later.
TSSLServerSocket matches a client certificate against the address the
connection arrived from, and test/keys/client.crt carries no subjectAltName,
so every *-ip-ssl case with a Python server fails: py-py, py-cpp, py-rb,
py-rs, py-nodejs and py-kotlin.

test/keys/client_v3.crt exists for exactly this case. It carries 127.0.0.1,
::1, ::ffff:127.0.0.1 and localhost, which covers every peer address the
servers actually see.

Presenting it is not enough on its own. Every certificate under test/keys
carries the same distinguished name and none carries an authority key
identifier, so OpenSSL treats each one as self-signed and never chains it to
CA.pem. A certificate is accepted only when the verifying side holds that
exact certificate, and a store keeps only one certificate per distinguished
name, so client.crt and client_v3.crt cannot both be trusted at once and the
servers have to move over together with the clients.

test/py/TestServer.py and test/rb/integration/TestServer.rb therefore trust
client_v3.crt, and every client that presents a certificate to them sends it:
Python, Ruby, Rust and Node.js were already changed, C++ follows here, and Java
and Kotlin through .clientkeystore, regenerated from client_v3 with the
algorithms that were already in it. Go sends no client certificate at all and
is unaffected; the Ruby server accepts that because it verifies without
VERIFY_FAIL_IF_NO_PEER_CERT.

client.crt is left unchanged so the Python unit tests keep exercising the
rejection path, where it is CLIENT_CERT_NO_IP.

Verified by running test/py/TestServer.py against test/py/TestClient.py over
binary/buffered/--ssl in three configurations: client.crt against the old store
fails on the address check, client_v3.crt against the old store fails with
unknown ca, and client_v3.crt against the new store passes. The Ruby context
was exercised the same way against both certificates, and the regenerated
keystore was read back with keytool.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 02:05:53 +02:00
John Sirois 6822d1a65f THRIFT-3606: Fix TSaslClientTransport constructor props parameter type.
Client: java

The `props` parameter is a pass through to `Sasl.createSaslClient` and
previously had a narrower type than required by `Sasl.createSaslClient`
which restricted use artificially.
2026-09-08 11:17:45 -07:00
Sylwester Lachiewicz 7d1df1e34d Remove obsolete thrift-maven-plugin and document standard Maven usage
Client: java

The thrift-maven-plugin in contrib has not been published since ~2017,
is not part of the release build or test procedures, and merely shelled
out to an externally installed thrift executable.

Remove the unmaintained plugin from contrib and document how to generate
Java Thrift code in Maven projects using standard exec-maven-plugin and
build-helper-maven-plugin in lib/java/README.md.
2026-09-07 09:16:50 +02:00
Jens GeyerandClaude Opus 5 827236ca25 Bound the SASL negotiation payload by frame size rather than message size
Client: java

receiveSaslMessage() reads a five-byte header and allocates the payload buffer
from the length it declares, before readAll blocks for the payload itself. It
runs during the handshake, so the peer choosing that length has not
authenticated yet, and the only bound was max message size -- 100 MB by
default, which describes a whole message rather than one negotiation header.

Bound it by max frame size instead. The nonblocking SASL server already holds
its own negotiation frames to that value (sasl/SaslNegotiationFrameReader), and
this is the same protocol, so the two paths now agree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 23:35:21 +02:00
Jens GeyerandClaude Opus 5 745a276b14 THRIFT-6181: Bound the response frame size in the Java async client
TAsyncMethodCall sizes the response frame from the four bytes the peer
sends ahead of it, with no check of any kind:

    if (sizeBuffer.remaining() == 0) {
      state = State.READING_RESPONSE_BODY;
      frameBuffer = ByteBuffer.allocate(TFramedTransport.decodeFrameSize(sizeBufferArray));
    }

decodeFrameSize returns a signed int, so the peer picks anything from
-2147483648 to 2147483647 and ByteBuffer.allocate is handed it. A negative
one raises IllegalArgumentException, which is not a TTransportException and
reaches the callback as it is; a large positive one is allocated, and
ByteBuffer.allocate zeroes the array, so the memory is resident rather than
reserved.

It is the odd one out among the three places lib/java reads a frame size.
TFramedTransport.readFrame and TFastFramedTransport.readFrame both refuse a
negative size and one over getMaxFrameSize(). AbstractNonblockingServer's
FrameBuffer refuses a size <= 0, one over trans_.getMaxFrameSize(), and on
top of that defers a frame that would push the server past
MAX_READ_BUFFER_BYTES. Only the async client takes the number as it comes,
so apply the same two checks with the same messages.

Worth a release note: maxFrameSize defaults to 16384000, so an async client
now refuses a response frame larger than that where it used to allocate it.
setMaxFrameSize raises the bound with it.

Three tests drive a real TAsyncMethodCall against a socket that answers
with a frame size and no body. They assert the buffer that was allocated
rather than only that the call failed, because a response body that never
arrives ends the call either way. Two fail before the change -- "allocated
65536 for a frame that is over the maximum", and "a negative size reached
ByteBuffer.allocate: java.lang.IllegalArgumentException: capacity < 0:
(-1 < 0)". The third reads a frame of exactly the maximum end to end and
passes either way.

Client: java

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:23:29 +02:00
Jens GeyerandClaude Opus 5 2e55fd53cf THRIFT-6182: Keep the configured maximum frame size when wrapping (Java)
Wrapping a transport in TFramedTransport or TFastFramedTransport overwrote
the maximum frame size it was configured with, even when no maximum had
been asked for:

    public TFramedTransport(TTransport transport) throws TTransportException {
      this(transport, TConfiguration.DEFAULT_MAX_FRAME_SIZE);
    }

    public TFramedTransport(TTransport transport, int maxLength) ... {
      TConfiguration _configuration = ...transport.getConfiguration();
      _configuration.setMaxFrameSize(maxLength);

So

    socket.getConfiguration().setMaxFrameSize(1024);
    TTransport framed = new TFramedTransport(socket);

left the socket configured for 16384000. Two things went wrong at once: a
maximum the operator set was replaced by the library default, and the
object written into belongs to the transport underneath, so anything else
sharing that TConfiguration changed with it. A layered transport has no
configuration of its own to write into -- TLayeredTransport.getConfiguration()
delegates to the inner transport by design.

TFastFramedTransport(underlying) and TFastFramedTransport(underlying,
initialBufferCapacity) did the same, as did TFramedTransport.Factory() and
TFastFramedTransport.Factory() / Factory(initialCapacity), so a server
configured with new TFramedTransport.Factory() raised the limit on every
connection it accepted.

Now a constructor or factory that was not given a maximum passes back the
one the transport already carries, so wrapping changes nothing. Given one
explicitly, the behaviour is unchanged: it is applied, as the argument's
javadoc promises.

Go solved this for its own deprecated constructors, and the reason is
written into its TConfiguration: noPropagation exists "to avoid overriding
underlying TTransport/TProtocol's cfg by accidental propagations". C++,
netstd, Delphi and Haxe all read the configured maximum and never write it.

Four tests in TestTFramedTransport, inherited by TestTFastFramedTransport
so both classes are covered: wrapping keeps a lowered maximum, the factory
keeps it, an explicit maximum is still applied, and -- the point of the
other three -- a frame declaring 2048 bytes is still refused by a transport
configured for 1024 after being wrapped. Three of the four fail on each
class beforehand; the explicit-maximum one is a regression guard and passes
either way.

Client: java

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:16:15 +02:00
dependabot[bot] 3768424b7d Bump com.diffplug.spotless from 8.8.0 to 8.10.0 in /lib/java
Bumps com.diffplug.spotless from 8.8.0 to 8.10.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-01 08:31:51 -07:00
Jens GeyerandClaude Opus 5 d10129d42a THRIFT-6165: Bind the Java read budget to the frame that carries the message
TFramedTransport and TFastFramedTransport read a frame header that tells them
the exact size of the message they are about to hand to the protocol, and never
tell the budget. checkReadBytesAvailable is therefore measured against
TConfiguration.maxMessageSize for the life of the connection, so a 68-byte frame
may declare a 64 MB field and the array is allocated before the shortfall is
found.

Binding it needs an API that does not exist. resetConsumedMessageSize(-1) is the
only genuine full reset and it is protected, so a layered transport cannot call
it on its inner transport; updateKnownMessageSize() refuses to grow a budget an
earlier smaller frame narrowed, and carries that frame's consumption forward
besides. So this adds resetMessageSizeAndConsumedBytes(long) to TTransport,
mirroring netstd's ResetMessageSizeAndConsumedBytes, implemented on
TEndpointTransport, delegated by TLayeredTransport, and a no-op on
TFileTransport alongside its existing no-op budget methods.

readFrame() then resets twice, for two different reasons. Before the framing
reads, because what is left of the previous frame's bound describes a frame we
are done with, and an inner transport that decrements on read -- TMemoryBuffer,
or the TMemoryInputTransport the nonblocking server uses -- would otherwise
refuse a frame larger than the last one. After them, binding to the frame,
discarding what the framing itself spent rather than charging it twice.

TMemoryInputTransport.reset() binds to the buffer it is given, as its
constructor already did. Reads there are clamped to the buffer and short-read
rather than checked against the budget, so this only tightens what the protocol
may declare.

The new abstract method is a source-compatibility break for anything extending
TTransport directly rather than through TEndpointTransport or TLayeredTransport;
four test doubles in this repository needed it.

Nine tests, eight of them written before the change, of which three fail
unmodified. The rest describe traffic that is legitimate today: the natural
implementation of frame binding breaks them, which is what makes them worth
having. The ninth records why the bound cannot go on the inner transport --
with the nonblocking server's shape, getting the frame off the wire spends the
inner budget entirely, and without the first reset the frame's own bytes are
then unreadable. 346 tests pass.

Unlike C++ (THRIFT-5371), Java does not accumulate across frames: the socket
path never decrements the budget on read, its only reset being the flush() one
on the write side. What it shares is the budget never being narrowed to the
frame.

Client: java

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 13:39:22 +02:00
Yuxuan 'fishy' Wang 10f18b7468 Update test certificates
Starting from go 1.27, it starts to enforce RFC 5280 IP SAN parsing [1],
and reject certs with IPv4-mapped IPv6 address.

Our pre-generated test certs contains one such IP (`::ffff:127.0.0.1`)
so it starts to fail in go test server when we update to go 1.27.

This change removes that IP from all the test certs and keep other
things in the test certs (mostly) intact, including all the private
keys, to prepare for the go 1.27 update.

[1]: https://github.com/golang/go/commit/a5b2a19336774bf0f59a0d43eafdb66b3f1c1c5b
2026-08-21 08:26:30 -07:00
dependabot[bot] a131700e4d Bump com.diffplug.spotless from 8.7.0 to 8.8.0 in /lib/kotlin (#3699)
Bumps com.diffplug.spotless from 8.7.0 to 8.8.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-01 22:20:45 +08:00
Jens GeyerandClaude Opus 5 c0442b9f85 Fix build for the JSON message-size test changes
Client: cpp,java

Two follow-ups to the recent TJSONProtocol message-size work:

lib/java: rewrap a javadoc comment in TestMessageSizeLimits so it matches
google-java-format; spotlessCheck rejected the previous wrapping.

lib/cpp: test_tthriftjsonprotocol_read_check_exception configured a message
size of 2 bytes, which the JSON reader now rejects while reading the container
element type name ("i32") rather than at the container size check the test
targets. readListBegin() then threw earlier in the stream than before and the
following readListEnd() hit an unexpected character. Raise the configured limit
so the container header is readable and enlarge the declared container so the
size check still exceeds the limit, keeping the original intent of the test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 01:57:27 +02:00
Jens GeyerandClaude Opus 4.8 845ffb605e Bound TJSONProtocol string and number reads by MaxMessageSize
Client: java

readJSONString() and readJSONNumericChars() decode a quote-delimited string and
a character-by-character numeric literal with no declared length, so unlike the
length-prefixed protocols they had no size gate and could grow without bound.
Track the running byte count and reject a single string or numeric literal once
it exceeds the configured MaxMessageSize, so it is bounded the way a
length-prefixed read already is. The count is compared against MaxMessageSize
directly rather than the decrementing remaining-message-size counter, so the
bound stays tight on the non-decrementing stream read path and does not further
tighten transports that already decrement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 22:43:59 +02:00
Jens Geyer b7b838d450 bump version number, fixed veralign.sh new/removed files 2026-07-11 17:56:59 +02:00
Jens GeyerandClaude Opus 4.8 76a94da65d Add a frame size limit to the SASL data-frame reader
Client: java

TSaslTransport.readFrame() allocated the data-frame buffer directly from the
wire-declared length, checking only for negative values. The SASL negotiation
phase (receiveSaslMessage) and the layered TFramedTransport already bound the
declared size by TConfiguration; apply the same getMaxFrameSize() limit here so
the post-handshake data path rejects a frame larger than the configured maximum
before allocating the buffer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 01:25:32 +02:00
Jens GeyerandClaude Opus 4.8 175e803d7e Add a configurable frame size limit to the SASL frame reader
Client: java

FrameReader allocated the payload buffer directly from the header-declared
size. The layered TFramedTransport already bounds incoming frames by
TConfiguration.getMaxFrameSize(); apply the same limit here so the SASL
negotiation and data frame paths reject a payload size larger than the
configured maximum before allocating the buffer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 01:25:05 +02:00
dependabot[bot] e5860a3278 Bump com.diffplug.spotless from 8.5.1 to 8.7.0 in /lib/kotlin
Bumps com.diffplug.spotless from 8.5.1 to 8.7.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-01 22:26:19 +02:00
dxbjavid deb36fa409 enforce stringLengthLimit in TCompactProtocol.readBinary 2026-06-24 23:15:36 +02:00
Jens GeyerandClaude Opus 4.8 dc8b269fa8 THRIFT-6054: Limit recursion depth in Kotlin struct, union and exception read/write
Client: java,kotlin

Kotlin-generated struct and exception serialization routes through
TProtocol.readStruct() and writeStruct() (the callback helpers in the shared
Java runtime), which did not bound recursion depth, so a deeply nested or
cyclic value was read or written without a limit. Kotlin-generated unions
extend the shared org.apache.thrift.TUnion, whose read/write path calls
readStructBegin()/writeStructBegin() directly and was likewise unbounded --
this affects Java-generated unions too.

Wrap the readStruct()/writeStruct() bodies, and TUnion's standard- and
tuple-scheme read/write bodies, in incrementRecursionDepth() / try ... finally /
decrementRecursionDepth(), reusing the existing TProtocol infrastructure (limit
from TConfiguration.getRecursionLimit(), default 64, TProtocolException.DEPTH_LIMIT
on excess). The Java generator emits an inline StandardScheme that already
increments separately and does not call the readStruct()/writeStruct() helpers,
so Java struct serialization is unaffected (no double-counting); only
Kotlin-generated code consumes them. A union's standard and tuple schemes are
mutually exclusive per protocol, so a union increments exactly once per level.

Replace the isolated counter test with a generated-code round-trip
(lib/kotlin RecursionDepthTest): the recursive types
CoRec/CoRec2/RecTree/RecUnion/RecError are generated from a new
src/test/resources/RecursionDepthTest.thrift (mirroring test/Recursive.thrift)
and driven through TBase.read()/write() -- chains at the limit round-trip,
chains one past it (write and read) are rejected with DEPTH_LIMIT for structs,
unions and exceptions, a wide structure confirms the counter is decremented per
sibling, and a cyclic graph is rejected instead of recursing without bound.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 22:54:30 +02:00
dependabot[bot] ed09a2255b Bump com.diffplug.spotless from 8.4.0 to 8.5.1 in /lib/kotlin
Bumps com.diffplug.spotless from 8.4.0 to 8.5.1.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-01 23:34:13 +02:00
Jens GeyerandClaude Sonnet 4.6 1dad55d654 Add decompressed byte tracking to Java TZlibTransport
Client: java

TIOStreamTransport.read() does not call checkReadBytesAvailable() or
countConsumedMessageBytes(), so TZlibTransport inherited no limit
enforcement on decompressed bytes despite having a TConfiguration.
Override read() in TZlibTransport to check the pre-read budget and
count every decompressed byte against remainingMessageSize so that
maxMessageSize is enforced cumulatively across the full session.

Also adds testMessageSizeLimit to TestTZlibTransport covering this path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 23:01:14 +02:00
Jens GeyerandClaude Sonnet 4.6 16b3673827 Add message byte tracking to consumeBuffer() in Java transports
Client: java

- consumeBuffer() in TMemoryInputTransport and AutoExpandingBufferReadTransport
  now decrements remainingMessageSize inline so fast-path buffer reads are
  counted toward the per-message size limit
- AutoExpandingBufferReadTransport.fill() resets remainingMessageSize at the
  start of each frame, matching TMemoryInputTransport.reset() behavior in
  TFramedTransport
- TBinaryProtocol.readString() now checks stringLengthLimit before the
  fast-path branch
- Add TestMessageSizeLimits covering all fixed code paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 02:00:50 +02:00
Dmytro ShteflyukandOpenAI Codex 794c78c63f Fix Java Spotless formatting
Client: java

Co-Authored-By: OpenAI Codex (GPT-5.4) <codex@openai.com>
2026-04-26 12:32:19 +01:00
Jens GeyerandClaude Sonnet 4.6 deeebfac25 Connect skip() to TConfiguration recursion limit
Client: java
Patch: Jens Geyer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

This closes #3415
2026-04-25 23:14:54 +02:00
Jens GeyerandClaude Sonnet 4.6 735a976aee Use bounded default for maxSkipDepth in TProtocolUtil
Client: java

TProtocolUtil.skip() previously defaulted to Integer.MAX_VALUE for its
recursion limit, making it effectively unbounded. This change aligns
the default with C++, Go, and Node.js (all use 64) by setting
maxSkipDepth to 64. Applications needing deeper nesting can still call
setMaxSkipDepth() to raise the limit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 22:39:02 +02:00
Jens GeyerandClaude Sonnet 4.6 d5152211af Add byte-count limit to TCompactProtocol varint reader
Client: py,go,php,java,netstd,delphi,haxe,lua,swift,rb,dart,erl,rs

C++ and Node.js already enforce a 10-byte ceiling on varint reads.
This change brings all remaining runtimes into parity by raising a
protocol exception (INVALID_DATA) when more than 10 bytes are consumed
without finding a terminating byte.

Java: both fast-path and slow-path varint readers are covered.
Erlang: read_varint/3 gains a when Count < 10 guard clause; call sites
  updated to propagate the error tuple rather than crashing on badmatch.
Rust: VarIntReader trait replaced with local bounded loops; zigzag
  decode moved to free functions independent of the integer_encoding crate.
Ruby: both the pure-Ruby implementation and the C extension are fixed;
  read_varint32 gains a separate 5-byte limit instead of delegating to
  read_varint64.

Named constants replace bare integer literals in all runtimes, with a
comment explaining the derivation (ceil(64/7) = 10, ceil(32/7) = 5).
Java and Rust enforce both the 5-byte (32-bit) and 10-byte (64-bit)
limits; other runtimes enforce the 10-byte ceiling uniformly.

Tests added for py, go, php, java (all four original runtimes), plus
rb, swift, dart, and rs which have existing unit-test infrastructure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 22:20:06 +02:00
Jens GeyerandClaude Opus 4.6 e0b830915a Enable TLS hostname verification in TNonblockingSSLSocket
Client: java

Set EndpointIdentificationAlgorithm to HTTPS on the SSLEngine parameters
in the TNonblockingSSLSocket constructor so that the server certificate
CN/SAN is validated against the target hostname during the TLS handshake.
This mirrors the behavior of TSSLTransportFactory.createClient() and
aligns the async SSL client with the sync client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 21:48:34 +02:00
Jens GeyerandClaude Opus 4.6 0919c3d550 Enable TLS hostname verification in TSSLTransportFactory
Client: java

Set EndpointIdentificationAlgorithm to HTTPS on SSLSocket parameters
in createClient() so that the server certificate CN/SAN is validated
against the target hostname during TLS handshake.

(03)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 00:20:04 +02:00
Jens Geyer 2e3afbe577 branch for release 2026-04-08 00:05:45 +02:00
dependabot[bot] 197da843af Bump com.diffplug.spotless from 8.2.1 to 8.4.0 in /lib/kotlin
Bumps com.diffplug.spotless from 8.2.1 to 8.4.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 22:14:03 +02:00
CJCombrink 45b6935a80 THRIFT-5925: Java UUID fix
Client: Java
Patch: CJCombrink

This closes #3334

- Using gradle spotlessApply

Adding a decorator to assist with code that used the uuid field already in Java
- For those who can't migrate to new UUID format
- Also captures the code that was used before

Fix UUID implementation in Java to be according to the Thrift UUID specification
- Don't do byte swapping when writing to and reading from the wire.
- This is a breaking change for anyone using UUID between Java servers
- For users that depends on this behaviour a TProtocolDecorator can be used to get back the old behaviour
2026-03-11 00:08:25 +01:00
shang 6721241272 Update the ProcessFunction::getResult method to return the _result type instead of a general TBase 2026-02-20 00:15:59 +01:00
dependabot[bot] 4966d0748b Bump com.diffplug.spotless from 8.1.0 to 8.2.1 in /lib/kotlin
Bumps com.diffplug.spotless from 8.1.0 to 8.2.1.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.2.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-07 00:09:05 +01:00
Hasnain Lakhani 10d9272600 THRIFT-5916: Enforce recursion depth limit in Java for C++ parity (#3287)
Java had TConfiguration.recursionLimit (default 64) and
TProtocolException.DEPTH_LIMIT defined but the limit was not actually
enforced during struct deserialization. This brings Java in line with
C++ which already enforces recursion limits.

Changes:
- Add recursionDepth_ counter and increment/decrement methods to TProtocol
- Modify Java code generator to emit try-finally depth tracking in
  generate_standard_reader() and generate_java_struct_tuple_reader()

Structures exceeding the configured recursion limit now throw
TProtocolException(DEPTH_LIMIT) during deserialization.
2026-01-26 07:37:03 -08:00
HTHou 098c82722b fix cross test error 2026-01-07 22:31:52 +01:00
HTHou b5919dd8f7 Add async nonblocking ssl support in java client 2026-01-07 22:31:52 +01:00
Dmytro Shteflyuk 312cef913c Updated Java keys for cross-platform tests
The truststore and keystore were regenerated using keys in test/keys:

    # keytool does not support "replace" operation:
    keytool -delete \
        -alias localhost \
        -keystore lib/java/src/crossTest/resources/.truststore \
        -storepass thrift
    keytool -import \
        -alias localhost \
        -file test/keys/CA.pem \
        -keystore lib/java/src/crossTest/resources/.truststore \
        -storepass thrift

    # server keystore
    keytool -importkeystore \
        -srckeystore test/keys/server.p12 \
        -srcstoretype PKCS12 \
        -srcstorepass thrift \
        -destkeystore lib/java/src/crossTest/resources/.serverkeystore \
        -deststoretype pkcs12 \
        -deststorepass thrift

    # client keystore
    keytool -importkeystore \
        -srckeystore test/keys/client.p12 \
        -srcstoretype PKCS12 \
        -srcstorepass thrift \
        -destkeystore lib/java/src/crossTest/resources/.clientkeystore \
        -deststoretype pkcs12 \
        -deststorepass thrift

Java tests were updated to use separate keystores for client and server.
2025-12-16 23:11:24 +01:00
dengzh b940d1229b THRIFT-5863: Make TServerTransport able to customize the max message size 2025-12-11 23:08:48 +01:00