On Fri, Mar 27, 2026 at 10:00 AM Oleg Kalnichevski <[email protected]> wrote:
> There is absolutely no guarantee there is a way to build a reasonable > HTTP/2 transport using classic i/o given its nature and inherent > limitations. If one ends up having to have a dedicated thread per H2 > stream it is not going to work and scale well no matter how cheap > virtual threads are. > I agree that HTTP/2 is the sticking point due multiplexing and support for full-duplex streaming. However, keep in mind that Go implements HTTP/2 exactly as you're describing. There's a connection-level read loop that does blocking frame reads and dispatches frames to the appropriate stream: https://github.com/golang/go/blob/4f62ef0625628e52d56779803805ca125ce34230/src/net/http/internal/http2/transport.go#L2097 And the write path similarly spawns a goroutine that writes the request and then waits for the response: https://github.com/golang/go/blob/4f62ef0625628e52d56779803805ca125ce34230/src/net/http/internal/http2/transport.go#L1310 This doesn't translate directly to Java since Go's `select` statement is inherently multiplexed and can block on multiple channels simultaneously (closest thing we have is `CompletableFuture.anyOf()` from Java 9), but it's an interesting proof-of-concept for an HTTP/2 implementation built entirely on stackful coroutines. We also have the option of retaining the event loop for connection-level code, while migrating higher-level code in the async client (such as route establishment) to the blocking implementation used by the classic transport. The point is that virtual threads are a huge opportunity to consolidate the classic and async implementations, and we're mainly limited by the performance of virtual threads compared to the callback-based implementation. I understand that Amazon has no interest in our server-side components. > That is fine. This proposal however directly conflicts with the > project's charter however outdated it is these days. You will have to > start off by drafting a new charter, getting it voted upon and > approved. One should also consider dropping `HttpComponents` name as no > longer reflective of the project scope and purpose and re-branding it > back as `HttpClient` as it originally was prior to the year 2005. > If people are getting use out of the server-side components then I don't want to drop them. What I *do* want is to make the core-client boundary easier to maintain, if possible. We have a lot of heavily overloaded methods and constructors and so on in order to preserve core's ABI compatibility with older versions of client. I'm not sure what to do about this. Would the existing charter allow us to consolidate core and client into a single repository and release train? Lockstep versioning of the core and client modules might allow us to relax backwards compatibility for the @Internal APIs in core. In this case one should also _seriously_ consider dropping the entire > core module except for protocol code and porting it to Netty. > Rationally that would be the best decision to ensure there is a future > for the project long-term. At the same you would likely need to attract > new people to the project as some of the old project members may not be > willing to stick around. Some degree of Netty integration is definitely worth considering. However, a Netty dependency will increase CVE churn, both for the project itself and its users. I see, and sometimes deal with, regular fire drills for Netty, Tomcat, etc., so I appreciate that HttpComponents doesn't create additional work for me. The best of both worlds would be optional Netty integration, provided through a custom transport layer facility (kind of a generalization of DetachedSocketFactory). This would allow us to still ship a secure, portable, pure Java client with a minimal dependency closure, while also providing optional access to advanced features that might never be exposed through Java's abstractions. The work on UDS and Windows named pipes is instructive regarding some of the difficulties here: the classic/async split prevents code reuse; `java.net.Socket` is almost impossible to extend; a `Selector` can't mix JDK and third party SocketChannels; etc.
