8397 Commits
Author SHA1 Message Date
Jens GeyerandClaude Opus 5.5 7cff696523 Consult IP subjectAltName entries only for an address host in the D TLS client
Client: d

thrift.internal.ssl.authorize() offered a certificate's IP subjectAltName
entries to the access manager on every connection, compared against the
address the socket is connected to. For a client opened with a host name that
is the address the name resolved to, so TDefaultClientAccessManager accepted a
certificate that named that address but not the name.

The IP entries are now consulted in client mode only when the host is itself
an address literal (RFC 9525 6.1.1). The host is classified the way the socket
resolves it, with getaddrinfo and AI_NUMERICHOST, so every numeric form the
socket connects to counts as an address and a name that only begins with a
dotted quad does not (RFC 9525 7.4). A client opened without a host and the
server side are unchanged. authorize() takes the side of the connection as a
new last parameter, and lib/d/README.md notes the change.

The new unittests run a handshake against test/keys/server.crt in memory and
ask authorize() about address literals, host names and no host, and check the
literal classification on its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 01:19:33 +01:00
Jens GeyerandClaude Opus 5.5 6eb663c32e Require a label after the wildcard in the D TLS name match
Client: d

matchName(), which backs TDefaultClientAccessManager, honoured a wildcard in
the leftmost label of a certificate name even when no label followed it, so
a dNSName or common name of "*", "f*" or "*." matched every single-label
host name. A wildcard stands in for the leftmost label of a longer name
(RFC 6125 6.4.3); a pattern whose wildcard label has no label after it no
longer matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 01:19:07 +01:00
Jens GeyerandClaude Opus 5.5 8bc32dc84f Require a label after the wildcard in the C++ TLS name match
Client: cpp

matchName(), which backs DefaultClientAccessManager, honoured a wildcard in
the leftmost label of a certificate name even when no label followed it, so
a dNSName or common name of "*", "f*" or "*." matched every single-label
host name. A wildcard stands in for the leftmost label of a longer name
(RFC 6125 6.4.3); a pattern whose wildcard label has no label after it no
longer matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 01:17:23 +01:00
Jens GeyerandClaude Opus 5.5 3807fae18b Compare an IPv4 subjectAltName entry by its bytes in the D TLS client
Client: d

TDefaultClientAccessManager.verify(Address, ubyte[]) cast the value of
InternetAddress.addr(), which is the IPv4 address as a number in host byte
order, to a pointer and compared the four bytes found there with the entry.
It now compares the address in network byte order, the order the certificate
carries it in. The IPv6 comparison is unchanged; the new unittest covers both
families.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 01:16:44 +01:00
Jens GeyerandClaude Opus 4.8 b2a506a52d Queue the response completion before making the request in the evhttp client channel
Client: cpp

evhttp_make_request() can invoke the response callback synchronously, for
example on an immediate connection failure, before sendAndRecvMessage() had
queued the completion; finish() then ran on an empty completion queue. The
completion is now queued before the request is made, and removed again if the
request does not start, so finish() always finds the matching entry. finish()
also returns early on an empty queue instead of reading from it. The container
is a std::deque so the entry just queued can be removed from the back without
disturbing other pending requests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-28 01:16:15 +01:00
Jens GeyerandClaude Opus 4.8 7f4f67cbff Reject an empty or out-of-range number in the C++ JSON protocol
Client: cpp

fromString() returned a value that extraction had never assigned when the
numeric token was empty, and returned a clamped value when the token was
outside the target type's range, because it tested only bad() and eof(). It
now value-initialises the result and tests fail(), so an empty token and an
out-of-range value both raise a TProtocolException through readJSONInteger()
and readJSONDouble() instead. Two cases in JSONProtoTest cover them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-28 01:15:49 +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
Zibran Khan 1152f1b569 THRIFT-6261: Reject negative sizes in the PHP TCompactProtocol reader Client: php
readCollectionBegin, readMapBegin and readString took the size straight
from readVarint, which accumulates into a 64-bit int and so decodes a
ten-byte varint with its last payload bit in bit 63 to a negative value.
They now raise NEGATIVE_SIZE for it, as the TBinaryProtocol readers
already do.
2026-10-28 01:09:08 +01:00
Jens GeyerandClaude Opus 5.5 6d04c10868 THRIFT-6461: Do not follow redirects from https to http in THttpClient
Client: go

A client without a CheckRedirect of its own, such as http.DefaultClient,
now stops at a redirect from https to http, as the HttpClient of .NET
does; other redirects and a CheckRedirect set by the caller work as
before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 01:05:52 +01:00
3d15fac3b9 THRIFT-6460: Match IP subjectAltName entries only for an address host in TSSLSocket
Client: cpp

TSSLSocket::authorize() offered a certificate's IP subjectAltName entries to
the AccessManager on every connection, compared against the address returned
by getpeername(). In client mode that is the address the configured host
resolved to, so a client opened with a host name accepted a certificate that
named only that address.

The IP entries are now consulted in client mode only when the host the socket
was opened with is itself an address literal, recognised the way
TSocket::open() resolves it: getaddrinfo() with AI_NUMERICHOST. Connecting to
an address literal, server mode, and a socket opened from a descriptor with no
host are unchanged. An AccessManager of your own is not asked about IP entries
for a client opened with a host name.

Adds regression cases to SecurityTest, aligns the AccessManager documentation
in TSSLSocket.h and lib/cpp/README.md, and notes the change under Breaking
Changes for 0.26.0.

Co-Authored-By: Jens Geyer <jensg@apache.org>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 00:35:43 +01:00
Sylwester LachiewiczandClaude Opus 5.5 73b172c8e5 THRIFT-6458: Fix the c_glib warnings in the library, its tests and generated code
Client: c_glib

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 00:20:54 +01:00
dajiaohuang 8079734057 THRIFT-6409: Keep TJSONProtocol stack aligned after empty lists
Client: js

Generated-by: Pi 1.4.0 (openai-codex/gpt-6-luna)
2026-10-28 00:14:15 +01:00
Sylwester LachiewiczandClaude Opus 5.5 040998f89d THRIFT-6455: Install only what the CMake compiler CI job builds with
Client: build

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 23:37:40 +01:00
Dmytro ShteflyukandOpenAI Codex 784915e3cf THRIFT-6453: Allow bounded write staging in Ruby BufferedTransport (#4049)
Client: rb

Add an opt-in write_buffer_size to BufferedTransport and its factory. Coalesce small writes and drain local staging through downstream writes while preserving explicit flush boundaries and the existing default buffering behavior.

Co-authored-by: OpenAI Codex (gpt-6.1-sol) <codex@openai.com>
2026-10-27 09:15:21 -04:00
Zibran KhanandClaude Opus 5.5 06773440c2 Document redirect handling of THttpClientOptions.Client
Client: go

Describe how the configured http.Client handles redirects when its
CheckRedirect is nil, including which headers set through SetHeader are
sent along, and how to restrict or disable redirects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 21:08:35 -07:00
Sylwester LachiewiczandClaude Opus 5.5 f0eb8b84eb THRIFT-6385: Skip the RLIMIT_AS test case where the limit is unsupported
Client: cpp

macOS rejects an RLIMIT_AS limit with EINVAL, so the child always exited with 2
and the case failed there. The child now exits with 77 in that case and the
case reports that it has nothing to check; any other setrlimit failure still
fails it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:32:40 +02:00
Viacheslav KoryaginandOpenAI Codex f7424439fd THRIFT-6445: Add ability to mark enums as flags
Client: py,netstd

Co-Authored-By: OpenAI Codex (GPT-6) <noreply@openai.com>
2026-10-24 15:30:21 +02:00
Jens GeyerandClaude Opus 5.5 8cc3038793 Keep System.ServiceModel.Primitives at 8.x in the net8/net9 compile tests
Client: netstd

10.x ships no net8.0 reference assemblies, so net8.0 and net9.0 resolve
the empty ref/netcoreapp2.0 placeholder and the generated WCF attributes
no longer compile. Restores the pin from 8c00c6489.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 15:16:42 +02:00
Jens Geyer 58cee63f89 netstd bump versions 2026-10-24 15:16:42 +02:00
Dmytro ShteflyukandOpenAI Codex 8b2ad3e85a THRIFT-6451: Reduce temporary allocations when reading Ruby JSON strings (#4045)
Client: rb

Use transport byte reads for string bodies and share frozen escape tables.
Document read_byte requirements for custom read hooks in 0.26.0.

Co-authored-by: OpenAI Codex (gpt-6.1-sol) <codex@openai.com>
2026-10-24 08:42:25 -04:00
Dmytro ShteflyukandOpenAI Codex 0a8eb9a5cb THRIFT-6449: Reduce allocations during Ruby recursive type checking (#4043)
Client: rb

Check accepted classes directly and reuse diagnostic paths within each
container traversal to avoid per-element temporary objects.

Co-authored-by: OpenAI Codex (gpt-6.1-sol) <codex@openai.com>
2026-10-23 06:47:58 -04:00
Dmytro ShteflyukandOpenAI Codex a7cd2ffe69 THRIFT-6447: Normalize Ruby union field selectors (#4041)
Client: rb

Convert constructor field names to Symbols so generated union constants
and defaults support field access and preserve equality across serialization.
Add regression coverage for String selectors, generated values, and protocol
round trips.

Co-authored-by: OpenAI Codex (gpt-6.1-sol) <codex@openai.com>
2026-10-23 06:44:34 -04:00
Dmytro ShteflyukandOpenAI Codex 1090cc49f6 THRIFT-6446: Preserve list elements in the pure-Ruby set writer (#4042)
Client: rb

Iterate legacy Hash-style sets by key and other sets by element,
preserving nested lists without destructuring them.

Add regression coverage for Set, Set subclasses, Array, and Hash
representations across Binary, Compact, and JSON protocols.

Co-authored-by: OpenAI Codex (gpt-6.1-sol) <codex@openai.com>
2026-10-23 06:42:35 -04:00
Jens GeyerandClaude Opus 5.5 55d53e057b THRIFT-6444: Make TSocket on the Haxe js target receive replies
Client: haxe

The WebSocket arm of TSocket (js target) could send but never receive:
- read() started its copy loop at len, so it returned len without
  appending a single byte;
- it read every value from the start of the received message instead
  of from where the previous read stopped;
- the received data was a Blob, the WebSocket default, or before any
  message the WebSocket itself; neither has get();
- flush() called back right after sending, before the reply had
  arrived, so a generated client never saw it;
- a call made right after open() failed with "Sent before connected",
  because the WebSocket connects asynchronously.

Messages now arrive as ArrayBuffer and are read in order from where the
last read stopped. A flush callback waits for the message that carries
the reply, a flush before the connection is up is sent once it is, and
callbacks still waiting when the connection closes get an error. The
other targets are unchanged.

lib/haxe/test gains WebSocketTest, which websocket.mjs runs under Node
against a minimal WebSocket server that answers ThriftTest calls. The
lib-haxe-codegen job runs it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 11:16:01 +02:00
Jens GeyerandClaude Opus 5.5 a2748940bd THRIFT-6440: Let the .NET tool run where only .NET 9 or later is installed
Client: build

Apache.Thrift.Compiler targets net8.0 and set no RollForward, so on a
machine with only .NET 9 or 10 the tool installed and then refused to
start, asking for .NET 8. With RollForward=Major the launcher uses the
next newer .NET when 8 is missing; where 8 is installed, nothing
changes.

test-dotnet-tool.ps1 now checks the runtimeconfig.json in the package.
The CI runners have .NET 8 next to newer versions, so installing and
running the tool there could not show the problem.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 09:57:28 +02:00
dependabot[bot] 50b43e6598 Bump markdown-it from 14.3.2 to 14.3.3
Bumps markdown-it from 14.3.2 to 14.3.3.

---
updated-dependencies:
- dependency-name: markdown-it
  dependency-version: 14.3.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-22 23:12:51 +02:00
Jens GeyerandClaude Opus 5.5 9931271628 THRIFT-6443: Count a client dropped while sending in the dispatch_rejection test
Client: cpp

With a non-blocking dispatch, serve() rejects and closes a client right
after accepting it, while the test client may still be writing its
request. When the close got there first, the send failed, the test
discarded that client, and if that happened to every rejected client
the check found no drop. too_many_pending_tasks_does_not_end_the_server
failed that way in about a third of the Windows CI jobs.

A fired client whose send fails with a transport error other than a
timeout now counts as dropped, like one that reads end-of-stream or a
reset.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 22:24:53 +02:00
Jens GeyerandClaude Opus 5.5 e071ceb822 THRIFT-6441: Link the current Visual C++ Redistributable from the installer and the .NET tool
Client: build

https://aka.ms/vs/17/release/vc_redist.x64.exe serves the Visual Studio
2022 redistributable, 14.44.35211 at the moment, while the WinGet and
Chocolatey packages ask for 14.51 or later (THRIFT-6401): the runtime
has to be at least as new as the build tools the compiler was built
with. Microsoft's permalink to the latest version is
https://aka.ms/vc14/vc_redist.x64.exe, which serves 14.51.36247. The
installer, the .NET tool's launcher and its README now name that one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 22:22:06 +02:00
Jens GeyerandClaude Opus 5.5 85cb2694ad Describe the prebuilt Windows compiler in README.md [skip ci]
The Installation section only covered building from source. A new
subsection lists the ready-built ways to get the compiler on Windows:
Chocolatey, the Apache.Thrift.Compiler .NET tool, the installer on the
GitHub release and the plain executable on the download page. It also
names the Visual C++ Redistributable the compiler needs, and what to do
when the .NET tool asks for .NET 8 although a newer .NET is installed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 22:21:14 +02:00
Dmytro ShteflyukandOpenAI Codex d01c127d0a THRIFT-6438: Name Ruby server threads (#4031)
Client: rb

Assign dotted role names to threads created by the Ruby servers.
Number pooled workers by creation order within each server run,
including replacement workers, while preserving application thread names.

Co-authored-by: OpenAI Codex (gpt-6.1-sol) <codex@openai.com>
2026-10-21 06:52:00 -04: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 47fe9968f6 Hand the raised exception to its wrapper instead of copying it
Client: php

The accelerator builds the exception it raises on a refused read in a local zval and wraps it for the throw, but the wrapper copied the object instead of taking it over, so the local reference was never released. Hand the object to the constructor that takes over the reference, as the other throw sites in this file already do.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 01:09:41 +02:00
Jens GeyerandClaude Opus 4.8 410e7863cf Report WebSocket and XHR client decode errors through the connection error event
Client: nodejs

A response the client cannot route -- an out-of-range sequence id, a wrong
protocol version, or input that is not JSON -- is now delivered to the
connection's "error" listeners instead of thrown out of the socket callback,
matching the TCP connection's decode loop. A sequence id that is not a safe
integer is refused before the per-service lookup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 01:08:58 +02:00
Jens GeyerandClaude Opus 4.8 65ac624e62 Resume the JSON message scan across fragments and bound its nesting depth
Client: nodejs

TJSONProtocol.readMessageBegin now keeps its scan state on the transport, so a
message that arrives in several pieces is scanned once instead of from its first
byte on every piece, and a message nested past a fixed limit is refused before
it reaches json_parse.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:59:59 +02:00
Jens GeyerandClaude Opus 4.8 819e1cda1d Read a buffered binary or compact message once rather than on every piece
Client: nodejs

readMessageBegin now walks the argument struct to confirm the whole message
has arrived before the generated reader decodes it, and resumes that walk across
pieces, so a message that arrives in several pieces is read once instead of from
its first byte on every piece.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:52:35 +02:00
Jens GeyerandClaude Opus 4.8 16e9f4c4e5 Keep TThreadedServer serving when a worker thread cannot be started
Client: cpp

TThreadedServer::onClientConnected() inserts the new client into its active-client
map and then starts a worker thread for it. When the thread cannot be started --
the process is out of threads, so std::thread's constructor throws -- two things
went wrong on the default (non-detached) configuration:

  - Thread::start() had already run setState(starting) but left thread_ null, and
    ~Thread()/join() dereferenced thread_ unconditionally for a non-detached thread,
    so destroying the failed worker crashed.
  - The exception is not a TTransportException, so the accept loop's only catch did
    not handle it; it unwound out of serve() and the server stopped accepting, with
    the client left in the active-client map.

Null-guard ~Thread()/join() so a never-started thread can be destroyed safely, and
catch the failure in onClientConnected(), remove the client from the map, and keep
serving -- the way TThreadPoolServer drops one client on a rejected dispatch and
continues.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:46:32 +02:00
Sylwester LachiewiczandClaude Opus 5.5 858afbe43d THRIFT-6384: Read a -remote container argument by its field id, not its position
Client: go

The Go -remote stub decoded a container argument with ReadField<position>, but
the args struct names its read methods after the field id, so the stub did not
compile when a container argument's id differs from its position or is implicit
(ReadField_N). Apache IoTDB's confignode.thrift hits both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 00:24:24 +02:00
Sylwester LachiewiczandClaude Opus 5.5 feab152782 THRIFT-6380: Keep configure and build output out of the source tarball
Client: build

Directories that EXTRA_DIST names whole also carry what configure, the build and
rebar3 left in them, so the 0.25.0 tarball shipped lib/d/src/base.o, config.h, 25
configured Makefiles and test/erl/_build. dist-hook now removes them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 00:22:59 +02:00
Sylwester LachiewiczandClaude Opus 5 a9d46268b0 THRIFT-6348: Go tests: stop writing ThriftTest.thrift copies into the source tree
Client: go

lib/go/test wrote a filtered copy next to the sources and test/go a
plain one; both were gitignored, so a checkout's IDL set depended on
whether a build had run. Write the filtered copy under build/ and
resolve the include with -I; use test/ThriftTest.thrift directly in
test/go.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-21 00:18:20 +02:00
Jens GeyerandClaude Opus 4.8 8391902c9b Ratify the Q59 resource-use threshold in the threat model [skip ci]
Record Q59 (the P10 resource-use threshold) as ratified by the PMC: given the caps
are set, memory or CPU that grows super-linearly with the size of the input is a
bug; growth by a constant factor against the caps is not; a missing cap remains a
bug; a hang on streaming input with no cap set is the operator's choice. Capture it
under P10 "Threshold" with the four qualifications, flip the Section 9 fuzz
disposition and the YAML threshold accordingly, and keep the Section 14 Q59 analysis
as the reasoning behind the line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:17:05 +02:00
Jens GeyerandClaude Opus 4.8 e0fa520ad0 Apply the string length limit when the accelerated decoder skips a string
Client: py

The accelerated binary and compact skip paths read a field's declared length and
pulled that many bytes through the transport without the length check the matching
read path performs; apply the same check so a skipped string field is bounded like
a read one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:07:26 +02:00
Jens GeyerandClaude Opus 4.8 8cf4a0fc9d Check the result of the commonName conversion in the TLS peer check
Client: d

ASN1_STRING_to_UTF8() returns a negative length and leaves its output
pointer untouched for a commonName whose string type it cannot convert.
The fallback loop now scopes that pointer to each iteration and consults
the length before the name is sliced or released.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:07:03 +02:00
Jens GeyerandClaude Opus 4.8 a3fe3126ad Finish handling a connection before it may be recycled in the nonblocking server
Client: cpp

TConnection::transition() can close a connection while a request is processed
inline, which returns the connection object to the server to be reused or
deleted; workSocket() then read the connection's members. transition() now
reports whether the connection is still owned by the calling I/O thread, and
workSocket() stops working the socket as soon as it is not.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:06:41 +02:00
Jens GeyerandClaude Opus 4.8 5217b8be57 Accept at most one transform in a THeader frame
Client: go

ZLIB is the only transform the header transport applies, and no sender
lists it more than once, so a well-formed frame carries at most one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:06:20 +02:00
Jens GeyerandClaude Opus 4.8 71194a070b Accept at most one transform in a THeader frame
Client: rb

ZLIB is the only transform the Header transport applies, and no sender
lists it more than once, so a well-formed frame carries at most one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:05:28 +02:00
Jens GeyerandClaude Opus 4.8 4bbf35694c Bound string and binary lengths on the PHP inlined read path
Client: php

TProtocol::skipBinary() and the readers that "--gen php:inlined" emits read a
string or binary length straight from the transport and then read that many
bytes. Hold the length to TProtocol::DEFAULT_MAX_STRING_SIZE first, through a
new TTransport::checkStringSize(), the same bound TBinaryProtocol applies on
the protocol read path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:05:15 +02:00
Jens GeyerandClaude Opus 4.8 299be75bac Accept at most one transform in a THeader frame
Client: py

ZLIB is the only transform the header transport applies, and no sender
lists it more than once, so a well-formed frame carries at most one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:05:03 +02:00
Jens GeyerandClaude Opus 4.8 12180b43f9 Report a set element or map key with no string form as a catchable error
Client: php

The accelerated reader converts a non-string set element or map key with
convert_to_string(), which runs user code and can leave a PHP error pending
when the element has no string form. Check for it right after the conversion
and propagate it, as the other Zend calls in the extension already do, so the
read finishes through its normal error path instead of leaving the error for
the input transport destructor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 00:01:42 +02:00
Jens GeyerandClaude Opus 4.8 79cc5cea19 Balance transport references and provide factory defaults in ThriftSimpleServer
Client: c_glib

The base thrift_transport_factory_get_transport() now returns an owned
reference, like the buffered, framed and zlib factories do, so the input
and output transports that ThriftSimpleServer releases after each
connection balance the references the protocols take on them.

The default transport and protocol factories are installed in a
constructed() handler rather than in instance init, so they survive the
processing of the construct-only factory properties; a server created
without explicit factories now has a factory for every accepted
connection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-20 23:59:10 +02:00
Jens GeyerandClaude Opus 4.8 0cc6d56cf5 Bound the container size and refuse the stop and unknown skip types
Client: st

skipType: returned without reading for the stop type and raised a bare Error for
any unrecognised type, so a list, set or map declaring stop as its element type
was iterated over its whole declared count while reading nothing, and a caller
guarding on the library error hierarchy missed an unrecognised type. Both now
raise a TProtocolError, and the binary protocol refuses a declared container
count above a finite, caller-settable maximum, as it already does for strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-20 23:58:46 +02:00