Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
ef2de4f
Add HTTP/2 support design specs
robotdan May 6, 2026
b9d48ca
Tighten HTTP/2 design spec after review pass
robotdan May 6, 2026
f3c7e1a
Add HTTP/2 implementation plans (A–F)
robotdan May 6, 2026
11f52c3
Apply pre-execution review feedback to HTTP/2 plans + specs
robotdan May 6, 2026
df5637c
Add HTTPValues.Status.ExpectationFailed (417) constant
robotdan May 6, 2026
49c184f
Update plan code samples to project's SPDX copyright header
robotdan May 6, 2026
741da81
Add failing test for Expect ≠ 100-continue returning 417
robotdan May 6, 2026
e99f0bc
Reject unsupported Expect values with 417 per RFC 9110 §10.1.1
robotdan May 6, 2026
bb8810a
Make ExpectTest byte-exact assertion resilient to Date-header changes
robotdan May 6, 2026
9b0a70e
Add HTTP/1.1 preamble conformance tests for already-correct parser be…
robotdan May 6, 2026
52455ec
Extract shared request/response capture in BaseSocketTest
robotdan May 6, 2026
d7602c4
Flip HTTP1.1.md conformance items closed by Plan A
robotdan May 6, 2026
d168777
Cleanup HTTP1.1.md Roadmap after Plan A completion
robotdan May 6, 2026
b36d6e7
Address Plan A final review: scope Roadmap claim; reorder BaseSocketT…
robotdan May 6, 2026
db948d3
Add HTTPValues.ForbiddenTrailers deny-list per RFC 9110 §6.5.2
robotdan May 6, 2026
c19a3d2
Add ProtocolSwitchHandler functional interface for 101 hook
robotdan May 6, 2026
ec59574
Add HTTPRequest.acceptsTrailers() helper for TE: trailers token-list
robotdan May 6, 2026
c4fd017
Add HTTPRequest trailer accessors (lazy-init, case-insensitive)
robotdan May 6, 2026
405920c
Use Locale.ROOT in HTTPRequest trailer toLowerCase calls
robotdan May 6, 2026
5246961
Add HTTPResponse trailer accessors with RFC 9110 deny-list
robotdan May 6, 2026
a26447c
Capture and parse chunked trailer fields with deny-list filtering
robotdan May 6, 2026
d9df9b9
Test that ChunkedInputStream silently drops forbidden trailer names
robotdan May 6, 2026
3f16ee2
Populate HTTPRequest trailer map from ChunkedInputStream on body EOF
robotdan May 6, 2026
eb9c8b5
Emit trailer-fields from ChunkedOutputStream when set
robotdan May 6, 2026
5334636
Wire response trailers through HTTPOutputStream
robotdan May 6, 2026
d845c83
Add HTTPResponse.switchProtocols(...) with 101 preamble + handler inv…
robotdan May 6, 2026
fb743e4
Address Plan B Task 10 review: tighten field layout and reject Connec…
robotdan May 6, 2026
6c33b7e
Flip HTTP1.1.md: trailers and 101 hook closed by Plan B
robotdan May 6, 2026
80a17ac
Move HTTPValues.ForbiddenTrailers to alphabetical position
robotdan May 7, 2026
af30d4a
Add HTTP2ErrorCode enum (RFC 9113 §7)
robotdan May 7, 2026
beea85a
Add HTTP2Settings holder with applyPayload(byte[])
robotdan May 7, 2026
719a486
Add HTTP2Frame sealed interface with per-type record variants
robotdan May 7, 2026
555d18f
Add frame and header-accumulation buffers to HTTPBuffers
robotdan May 7, 2026
2e882b9
Add HTTP2FrameReader with per-type validation and unknown-frame fallt…
robotdan May 7, 2026
70102ee
Add HTTP2FrameWriter; round-trip tests pass
robotdan May 7, 2026
60847b9
Add HPACKHuffman with RFC 7541 Appendix B static code table
robotdan May 7, 2026
b7f1539
Add HPACKDynamicTable with eviction on add and resize
robotdan May 7, 2026
3f03e4d
Add HPACKDecoder with full static table and 6 representation forms
robotdan May 7, 2026
f2809e5
Add HPACKEncoder; extract HPACKStaticTable shared with HPACKDecoder
robotdan May 7, 2026
af19b7e
Add HTTP2Stream state machine and window counters
robotdan May 7, 2026
e5a962d
Add flow-control accounting tests for HTTP2Stream
robotdan May 7, 2026
e662154
Address Plan C final review
robotdan May 7, 2026
03fa198
Introduce ClientConnection interface; rename HTTPWorker → HTTP1Worker
robotdan May 7, 2026
809544f
Add HTTP/2 enable flags to HTTPListenerConfiguration; configure ALPN …
robotdan May 7, 2026
8774a81
Add ProtocolSelector with TLS-ALPN and h2c prior-knowledge dispatch (…
robotdan May 7, 2026
2898fb6
Add HTTP2RateLimits with sliding-window counters for DoS classes
robotdan May 7, 2026
2294ed1
Add HTTP2Connection with preface validation and initial SETTINGS exch…
robotdan May 7, 2026
62c09e4
Add HTTP2InputStream and HTTP2OutputStream
robotdan May 7, 2026
a6dcfaa
Implement HTTP2Connection frame loop, HPACK header dispatch, handler …
robotdan May 7, 2026
50541b5
Add HTTP/2 basic integration tests via JDK HttpClient
robotdan May 7, 2026
0add3f7
Add HTTP/2 configuration knobs to HTTPServerConfiguration
robotdan May 7, 2026
955fb5f
Implement h2c via Upgrade/101 handoff in HTTP1Worker
robotdan May 7, 2026
e475055
HTTPRequest.isKeepAlive returns true for HTTP/2; strip h1.1-only resp…
robotdan May 7, 2026
bc1bff3
Add h2c prior-knowledge integration test; emit GOAWAY on graceful shu…
robotdan May 7, 2026
59cb2ba
Add HTTP/2 DoS / ALPN / raw-frame conformance tests
robotdan May 7, 2026
bc8de98
HTTP2.md: flip rows delivered by Plan D to implemented status
robotdan May 7, 2026
7ccf5be
Address Plan D final review
robotdan May 7, 2026
e8a8aa0
Add h2spec installer + test harness + int-h2spec Latte target
robotdan May 8, 2026
95598d6
Add H2SpecRunner standalone server entrypoint for ad-hoc h2spec runs
robotdan May 8, 2026
cca0127
Add grpc-java test deps + echo.proto with generated stubs
robotdan May 8, 2026
b316db7
Add GRPCInteropTest with unary + server-streaming over h2c and TLS+h2
robotdan May 8, 2026
d8a9e04
HTTP2.md: flip trailer rows for Plan E; record gRPC interop status
robotdan May 8, 2026
7c69499
Plan F setup: h2load installer + sample scenario + HTTP2.md/README h2…
robotdan May 8, 2026
d934635
Add gRPC client-streaming and bidi-streaming interop tests
robotdan May 9, 2026
cad7b5f
Fix HEADERS-flood OOM and closed-stream tracking (h2spec §5.1, §5.1.2)
robotdan May 9, 2026
86cea61
Capture full h2spec run: 77 failures across 20 sections
robotdan May 9, 2026
82b60b5
Add per-frame validators (h2spec batch 1)
robotdan May 9, 2026
f54282e
Add HPACK header validation per RFC 9113 §8.1.2.* (h2spec batch 2)
robotdan May 9, 2026
2850597
Connection-error GOAWAY ordering + state-machine RST_STREAM (h2spec b…
robotdan May 9, 2026
a5a0de6
HTTP2Settings.defaults: cap maxConcurrentStreams at 100 instead of In…
robotdan May 9, 2026
f835fc3
h2spec verification run: 138/147 passing (was 70/147)
robotdan May 9, 2026
2829cc4
h2spec final batch — half-closed-remote, GOAWAY ordering, flow-contro…
robotdan May 9, 2026
47457cc
h2spec final state: 143/147 passing (started 70/147)
robotdan May 9, 2026
9dd655f
Reduce TCP drain SO_TIMEOUT 500 ms → 50 ms in HTTP2Connection cleanup
robotdan May 9, 2026
d1d3d3d
Add perf baseline + fix top allocation hotspot in HTTPInputStream.dra…
robotdan May 9, 2026
2d43a4b
Add HTTP/2 benchmark scenarios + h2load dispatch in run-benchmarks.sh
robotdan May 9, 2026
a8a98e4
Enable h2c on Jetty/Tomcat/Netty benchmark servers
robotdan May 9, 2026
fba7ad8
Restructure README + update-readme.sh for h1.1 and h2 result tables
robotdan May 9, 2026
bb00915
Add HTTP/3 status doc — out of scope until JDK QUIC API or policy change
robotdan May 9, 2026
643256e
Run h1 + h2 benchmark matrix; populate README with real numbers
robotdan May 9, 2026
448ce71
Fix ProtocolSelector h1.1 fallback when h2c prior-knowledge is enabled
robotdan May 9, 2026
e26a7ae
Re-run h1 self benchmarks; update README with corrected numbers
robotdan May 9, 2026
de51903
Rigorous h1.1 hello (30s × 3): JIT noise, no regression
robotdan May 10, 2026
ba49878
Run rigorous h2 benchmark (30s × 3); update README with proper warmup…
robotdan May 10, 2026
4f3ed0d
Add TLS h2 (ALPN) benchmark scenarios
robotdan May 10, 2026
222066a
Fix Tomcat TLS cert path resolution in benchmark server.xml
robotdan May 10, 2026
a3dc29a
Fix benchmark vendor TLS cert paths (3 dots, not 2, from build/dist/)
robotdan May 10, 2026
b8983ed
Add jetty-alpn-java-server dep so Jetty's ALPNServerConnectionFactory…
robotdan May 10, 2026
1d8b95f
Fix h2load TLS dispatch: drop bogus --ca-file flag + cleanup on abort
robotdan May 10, 2026
9870ead
Perf: bodyless request fast-path, HPACK Huffman decode, ASCII lowercase
robotdan May 16, 2026
3b29aa0
Add h2 bench scenarios: compute, io, stream, plus connection-concurrency
robotdan May 19, 2026
d5cb7ff
Fix HTTP/2 rate-limit counter sharing across connections
robotdan May 19, 2026
5f26156
Perf: O(1) HPACK static table lookup + single-frame DATA flush fast path
robotdan May 19, 2026
228ccb0
Raise maxPendingSocketConnections default from 250 to 4096
robotdan May 19, 2026
bc0b8ce
Split HTTP2RateLimits into immutable config + per-conn tracker
robotdan May 19, 2026
d54f59a
docs: publish full-matrix benchmark numbers + 2026-05-19 perf findings
robotdan May 19, 2026
80ea73e
Add h2-large-response bench scenario + per-scenario design rationale doc
robotdan May 19, 2026
2423176
Publish cool-machine fair-rerun numbers; revise HTTP2.md Plan F item
robotdan May 19, 2026
93e18d3
Move full bench tables to docs/BENCHMARKS.md; keep README summary-only
robotdan May 19, 2026
1e1e55f
Address pre-PR review: HPACK bounds, frame buffer resize, module SPDX…
robotdan May 21, 2026
cda535f
Add Helidon WebServer 4.1.7 and Undertow 2.3.18.Final as benchmark ve…
robotdan May 21, 2026
99d65af
Publish 2026-05-21 perf numbers with Helidon + Undertow; document wri…
robotdan May 21, 2026
d72cd3d
Pre-merge fixes: HEADERS fragmentation, request trailers, handler-lea…
robotdan May 21, 2026
e56a297
Fix h2 request-trailer race by skipping FixedLengthInputStream on h2
robotdan May 21, 2026
75bdd18
Reject h2c-Upgrade requests with a body (smuggling guard)
robotdan May 21, 2026
5f023e9
Emit GOAWAY(INTERNAL_ERROR) on unhandled HTTP/2 reader exceptions
robotdan May 21, 2026
8224287
Signal reader when h2 writer thread dies to prevent deadlock
robotdan May 21, 2026
10d30fd
Prevent slow h2 handler from stalling the connection reader
robotdan May 21, 2026
b7ff2e2
Map HPACK index-0 and decode failures to GOAWAY(COMPRESSION_ERROR)
robotdan May 21, 2026
7957a10
Reject malformed h2 content-length with RST_STREAM(PROTOCOL_ERROR)
robotdan May 21, 2026
b01abb9
Visibility + safety polish across HTTP/2 and protocol-selector paths
robotdan May 21, 2026
d4ee843
Tighten h2 closed-stream HEADERS race and handler-RST drop logging
robotdan May 21, 2026
a313d79
Add h2 response-trailers wire test
robotdan May 21, 2026
98b86aa
Tolerate RST_STREAM on already-closed h2 stream
robotdan May 21, 2026
e131c22
Add pre-PR fix plan document
robotdan May 21, 2026
761e5ef
Merge remote-tracking branch 'origin/main' into robotdan/http2
robotdan May 21, 2026
270e70a
Replace Todos/Roadmap checkboxes with link to spec docs
robotdan May 21, 2026
164e7f2
Promote pre-PR fix decisions into docs/specs/HTTP2.md
robotdan May 21, 2026
a8ef048
formatting
robotdan May 22, 2026
f4e16c1
docs: add body-size config consolidation implementation plan
robotdan May 22, 2026
3d1633b
fix(http): use long arithmetic in HTTPInputStream boundary math to av…
robotdan May 22, 2026
e96d738
fix(http2): apply server MultipartConfiguration to per-request processor
robotdan May 22, 2026
3ecbede
fix(http2): enforce maxRequestBodySize on HTTP/2 requests
robotdan May 22, 2026
f51cc88
feat(multipart): add maxFileCount limit to MultipartConfiguration
robotdan May 22, 2026
39cf2cf
feat(server): validate maxFileSize against effective maxRequestBodySi…
robotdan May 22, 2026
e2ffa42
feat(multipart)!: remove MultipartConfiguration.maxRequestSize (use H…
robotdan May 22, 2026
599c387
docs: document maxRequestBodySize as single body cap; multipart confi…
robotdan May 22, 2026
92ee539
style(server): place validateConfiguration after public methods per c…
robotdan May 22, 2026
079c668
feat(http)!: widen maxRequestBodySize to long
robotdan May 24, 2026
ddd6db9
test(server): cover exact content-type key set to unlimited
robotdan May 24, 2026
a08e0e2
feat(http2): send RST_STREAM(NO_ERROR) after early 413
robotdan May 24, 2026
44e46ed
docs(http2): correct stale lost-wakeup finding; refocus Plan F on wri…
robotdan May 27, 2026
ab87ef8
perf(http2): wrap writer OutputStream in 64KB BufferedOutputStream
robotdan May 27, 2026
8d78e7d
refactor(http2): extract writer-thread loop body into runWriterLoop
robotdan May 27, 2026
8bc816c
docs(http2): correct runWriterLoop Javadoc — InterruptedException is …
robotdan May 27, 2026
d20a1d4
perf(http2): coalesce writer-thread queue drains into single-flush ba…
robotdan May 27, 2026
050d35d
docs(http2): note ThrowingOutputStream coupling to HTTP2FrameWriter w…
robotdan May 27, 2026
39d0a1b
fix(http2): emit GOAWAY(PROTOCOL_ERROR) for DATA on idle stream
robotdan May 28, 2026
92d774d
fix(http2): emit GOAWAY(PROTOCOL_ERROR) for WINDOW_UPDATE on idle stream
robotdan May 28, 2026
fe691cf
fix(http2): half-close output immediately after invalid-preface GOAWAY
robotdan May 28, 2026
6da910f
test(http2): address review feedback on HTTP2IdleStreamErrorsTest
robotdan May 28, 2026
43ff797
docs(http2): record 2026-05-27 writer-thread coalescing perf impact +…
robotdan May 28, 2026
0f7a0a5
docs(plans): land h2 writer-thread coalescing plan
robotdan May 28, 2026
e392d72
docs(http2): consolidate open follow-ups into a single scannable list
robotdan May 28, 2026
95e2aa0
fix(http2): harden HPACK decoder against malformed integers and overs…
robotdan May 28, 2026
6d1a1ca
fix(http2): enforce connection-level send flow control and atomic str…
robotdan May 28, 2026
d46c44b
docs(http2): refresh conformance summary, roadmap, and flow-control f…
robotdan May 28, 2026
ca3d84f
test(http2): prove per-stream flow control honors peer INITIAL_WINDOW…
robotdan May 28, 2026
0c2d1b2
docs(http2): track EOF-on-cancel and HPACK UTF-8 accounting; correct …
robotdan May 28, 2026
af1cff4
chore: Moving docs around based on the pattern for all Latte projects.
voidmain Jun 18, 2026
8333a53
fix: Refactored field parsing to unify everything
voidmain Jun 19, 2026
39c5a63
chore: Cleaning up constructs for reuse, removing unnecessary String …
voidmain Jun 19, 2026
8692915
chore: Moved classes into supackage to separate HTTP/1 from HTTP/2
voidmain Jun 21, 2026
301af7a
feat: Removed h2c upgrade support since it is officially deprecated a…
voidmain Jun 27, 2026
0cef07a
chore: whitespace
voidmain Jun 27, 2026
cf93430
docs: Design for moving protocol selection onto the virtual thread + …
voidmain Jun 27, 2026
adbad87
docs: Align naming table in protocol-selection design
voidmain Jun 27, 2026
911dd14
docs: Implementation plan for protocol-selection-on-vthread + naming …
voidmain Jun 27, 2026
8e06860
refactor: Rename ClientConnection interface to HTTPConnection and ext…
voidmain Jun 27, 2026
4b913dd
refactor: Rename HTTP1Worker to HTTP1Connection
voidmain Jun 27, 2026
1314801
refactor: Replace HTTP1Connection private WorkerState with HTTPConnec…
voidmain Jun 27, 2026
16ed464
refactor: Rename acceptor types (HTTPServerAcceptorThread, Connection…
voidmain Jun 27, 2026
7e59f5c
refactor: Hoist graceful shutdown() onto HTTPConnection, drop instanc…
voidmain Jun 27, 2026
d1d559f
refactor: Use primitive boolean prefaceConsumed in HTTP2Connection
voidmain Jun 27, 2026
4e90e4a
feat: Run protocol selection on the connection's virtual thread via C…
voidmain Jun 27, 2026
76bfa9b
test: Acceptor stays non-blocking while a TLS handshake stalls
voidmain Jun 27, 2026
629792e
test: Negotiating connections are bounded by SO_TIMEOUT, not reaped
voidmain Jun 27, 2026
ea07430
docs: Update HTTPConnection interface Javadoc for new implementors an…
voidmain Jun 27, 2026
7a307c5
refactor: Read delegate volatile directly in ConnectionDispatcher
voidmain Jun 28, 2026
1f9343b
feat: Move the code that does any blocking operations to the virtual …
voidmain Jun 28, 2026
93295c3
chore: Fixing the protocol selection to handle ALPN and preface bytes…
voidmain Jun 28, 2026
35af95d
chore: Moving and renaming constants.
voidmain Jun 28, 2026
b0d7257
chore: Clean up
voidmain Jun 28, 2026
77823f4
docs: Design for unified HTTPOutputStream with HTTP/2 compression
voidmain Jun 28, 2026
69e727d
docs: Implementation plan for unified HTTPOutputStream + HTTP/2 compr…
voidmain Jun 28, 2026
f71157a
refactor: Extract HTTPOutputProtocol seam; unify HTTP/1 output path
voidmain Jun 28, 2026
e915149
feat: Route HTTP/2 responses through unified HTTPOutputStream
voidmain Jun 28, 2026
a5bb3b0
test: HTTP/2 gzip/deflate compression parity
voidmain Jun 28, 2026
68be3e1
test: Assert Content-Length absent and Vary present on h2 deflate/str…
voidmain Jun 28, 2026
9c8e9fc
test: h2 compression+trailers frame-level test; document flush() cont…
voidmain Jun 28, 2026
ac14da4
docs: Restore and expand HTTPOutputStream public method Javadoc
voidmain Jun 28, 2026
b83a898
chore: cleanup
voidmain Jun 28, 2026
52ee57c
fix: Drain connection input on h2 teardown so close() sends FIN not RST
voidmain Jun 28, 2026
f8e79ad
fix: Flush h2 GOAWAY before teardown on graceful shutdown
voidmain Jun 28, 2026
8a6b990
chore: Refactored HTTP/1.1 preamble validation a bit and moved consta…
voidmain Jun 28, 2026
a4aa990
chore: Refactored settings encoding and decoding into the HTTP2Settin…
voidmain Jun 28, 2026
2caf70b
docs: design + implementation plan for HTTP2WriterThread extraction
voidmain Jun 29, 2026
32cf2fa
refactor: add HTTP2WriterThread and migrate writer-loop unit test
voidmain Jun 29, 2026
1ee87ff
refactor: route HTTP/2 outbound frames through HTTP2WriterThread
voidmain Jun 29, 2026
d886092
refactor: rename sendGoAwayDirect param to avoid HTTP2WriterThread fi…
voidmain Jun 29, 2026
845f0a6
chore: Moving some helpers around, cleaning up code, delegating flush…
voidmain Jun 29, 2026
b482ac4
docs: design for configuration cleanup (shared/HTTP1/HTTP2 split)
voidmain Jun 30, 2026
2b3d1b0
docs: implementation plan for configuration cleanup
voidmain Jun 30, 2026
e4dbb5e
feat: add HTTP1Configuration sub-config class
voidmain Jun 30, 2026
33037de
refactor: move HTTP/1 config to HTTP1Configuration sub-config
voidmain Jun 30, 2026
9df5e95
refactor: convert HTTP2RateLimits to public builder class
voidmain Jun 30, 2026
6d35a96
refactor: move HTTP/2 config to HTTP2Configuration and drop unwired k…
voidmain Jun 30, 2026
4e58378
refactor: remove deprecated server-level multipartBufferSize knob
voidmain Jun 30, 2026
77ef87c
docs: mark configuration cleanup design as implemented
voidmain Jun 30, 2026
5dec76e
chore: address final-review cleanups (doc §8, redundant imports, fram…
voidmain Jun 30, 2026
4f7f08e
chore: whitespace
voidmain Jun 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions .claude/rules/code-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ paths:

# Code Conventions

## Indentation

All source files should be indented with 2 spaces. Continuation indents should be 4 spaces.

## Acronym Naming

Always use full uppercase for acronyms in Java identifiers — class names, method names, field names, local variables. Do NOT use title-case (camelCase-with-only-the-first-letter-uppercase) for acronyms. If a field or method name starts with an acronym, lowercase the entire acronym.
Expand Down Expand Up @@ -82,7 +86,7 @@ module org.lattejava.web {

## Blank lines

Remove blank lines between fields.
Ensure there is one blank line between class members including fields, methods, and inner classes, interfaces, enums, records, etc.

### Example

Expand All @@ -101,6 +105,8 @@ public class Example {
}
```

Add blank lines between logical groups of operations in methods.

## Imports

Prefer module imports over class imports. If a class is using class imports, attempt to replace as many as possible with module imports.
Expand All @@ -119,7 +125,7 @@ import module java.base;

Add a blank line between import groups.

## Order inside classes
## Order inside classes and interfaces (not records)

Inside a class, the order should always be:

Expand All @@ -134,4 +140,10 @@ Inside a class, the order should always be:

## Javadoc

When Javadoc is written, use sentence structure, punctuation, and capitalization of common American English publications. This rule applies to @param, @return, @throws, and the main comment block.
When Javadoc is written, use sentence structure, punctuation, and capitalization of common American English publications. This rule applies to @param, @return, @throws, and the main comment block.

## Line length and wrapping

120 characters is the target line length. *DO NOT* wrap lines before 120 characters. If a line is longer than 120 characters, but keeping it on one line makes it easier to read, do not wrap it.

When wrapping lines, break on logical boundaries and avoid excessive wrapping. If breaking in an if-statement, break after the logical operator (`&&` or `||`). If breaking on chained method calls, break before the dot and align the dots with the dot of the previous line.
37 changes: 37 additions & 0 deletions .claude/rules/git.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
paths:
- "**/*"
---

# Git

When using Git for the project, follow these guidelines.

## Branching

Never commit directly to `main`. All work happens on a feature branch created from `main`; `main` only ever receives changes through a squash merge. This is a standard to follow by reading this file — it is intentionally not enforced by a hook.

Branch names should be descriptive and follow the format `<type>/<short-description>`. The `type` is the conventional commit type for the work, usually `feat`, `fix`, or `chore`.

## Squash merges

Always squash merge feature branches into `main`, so each unit of work lands as a single commit. Feature branches may be merged into other feature branches with a standard (non-squash) merge.

## Branch deletion

Always delete feature branches after merging them into another branch.

## Commit messages

Commit messages must follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/): `<type>[optional scope][!]: <description>`.

- Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`.
- Mark a breaking change with `!` after the type/scope (e.g. `feat!: …`) and/or a `BREAKING CHANGE:` footer.
- Because feature branches are squashed, the **squash commit message** is what lands on `main` and must itself be a single well-formed Conventional Commit. The per-commit messages on a feature branch must also follow the format (the `commit-msg` hook validates every commit).
- Trailers such as `Co-Authored-By:` are allowed; only the subject line is validated.

## Enforcement

Only the Conventional Commit format is hook-enforced, via a `commit-msg` hook in `.githooks/`. The `build` target points git at that directory automatically (`git config core.hooksPath .githooks`), so a single `latte build` activates it — no manual setup per clone. To activate it by hand without building: `git config core.hooksPath .githooks`.

The branching and squash-merge standards above are not hook-enforced; follow them by reading this file.
7 changes: 7 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

Zero-dependency HTTP server library for Java 21+ using virtual threads and blocking I/O (not NIO). Forked from FusionAuth's java-http. The HTTP client is not yet implemented.

## Documentation

- `docs/design/` — all design documents and specs (filenames prefixed with `YYYY-MM-DD-` creation date)
- `docs/implementation/` — all implementation plans (filenames prefixed with `YYYY-MM-DD-` creation date)

## Build System

This project uses the **Latte** build tool, not Maven or Gradle. The build file is `project.latte`.
Expand Down
102 changes: 42 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

* Latest stable version: `0.1.0`

The goal of this project is to build a full-featured HTTP server and client in plain Java without the use of any libraries. The client and server will use Project Loom virtual threads and blocking I/O so that the Java VM will handle all the context switching between virtual threads as they block on I/O.
The goal of this project is to build a full-featured HTTP server and client in plain Java without the use of any libraries. The server supports HTTP/1.1 and HTTP/2 (h2 over TLS via ALPN, h2c prior-knowledge or via Upgrade/101). The client and server will use Project Loom virtual threads and blocking I/O so that the Java VM will handle all the context switching between virtual threads as they block on I/O.

For more information about Project Loom and virtual threads, please review the following link.
* https://blogs.oracle.com/javamagazine/post/java-virtual-threads
Expand Down Expand Up @@ -165,70 +165,52 @@ A key purpose for this project is to obtain screaming performance. Here are benc

These benchmarks ensure `http` stays near the top in raw throughput, and we'll be working on claiming the top position -- even if only for bragging rights, since in practice your database and application code will be the bottleneck long before the HTTP server.

All servers implement the same request handler that reads the request body and returns a `200`. All servers were tested over HTTP (no TLS) to isolate server performance.

| Server | Requests/sec | Failures/sec | Avg latency (ms) | P99 latency (ms) | vs Latte http |
|----------------|-------------:|-------------:|-----------------:|-----------------:|--------------:|
| Latte http | 114,483 | 0 | 0.86 | 1.68 | 100.0% |
| JDK HttpServer | 89,870 | 0 | 1.08 | 2.44 | 78.5% |
| Jetty | 111,500 | 0 | 1.17 | 11.89 | 97.3% |
| Netty | 117,119 | 0 | 0.85 | 1.75 | 102.3% |
| Apache Tomcat | 102,030 | 0 | 0.94 | 2.41 | 89.1% |

#### Under stress (1,000 concurrent connections)

| Server | Requests/sec | Failures/sec | Avg latency (ms) | P99 latency (ms) | vs Latte http |
|----------------|-------------:|-------------:|-----------------:|-----------------:|--------------:|
| Latte http | 114,120 | 0 | 8.68 | 11.88 | 100.0% |
| JDK HttpServer | 50,870 | 17655.7 | 6.19 | 22.61 | 44.5% |
| Jetty | 108,434 | 0 | 9.20 | 14.83 | 95.0% |
| Netty | 115,105 | 0 | 8.61 | 10.09 | 100.8% |
| Apache Tomcat | 99,163 | 0 | 9.88 | 18.77 | 86.8% |
All servers implement the same request handler that reads the request body and returns a `200`. All servers were tested over plain HTTP (no TLS) to isolate server performance.

<!-- PERF-SUMMARY-START -->
Latte HTTP is competitive with the fastest production HTTP servers across most workloads. Where it pulls clearly ahead is the **blocking-IO scenario**, which simulates a handler waiting on a database, cache, or downstream HTTP call — the most common shape for real web apps. Virtual threads park for free; worker-pool servers (Tomcat, Jetty) are bottlenecked by their default thread-pool size.

**Headline scenario: `h2-io`** (handler does `Thread.sleep(10ms)` per request, 10 conns × 100 streams = 1000 in-flight)

| Server | Requests/sec | Errors | Avg latency (ms) | P99 latency (ms) | vs Latte http |
|---------------|-------------:|-------:|-----------------:|-----------------:|--------------:|
| Latte http | 70,676 | 125 | 13.94 | 19.41 | 100.0% |
| Latte http | 67,159 | 122 | 14.39 | 27.60 | 95.0% |
| Latte http | 69,337 | 52 | 14.22 | 25.88 | 98.1% |
| Helidon | 70,915 | 0 | 13.97 | 26.44 | 100.3% |
| Helidon | 69,149 | 0 | 14.15 | 32.11 | 97.8% |
| Helidon | 72,902 | 0 | 13.52 | 29.75 | 103.1% |
| Jetty | 11,249 | 84764 | 68.82 | 238.04 | 15.9% |
| Jetty | 11,305 | 85573 | 68.63 | 233.18 | 15.9% |
| Jetty | 10,530 | 81843 | 72.77 | 236.41 | 14.8% |
| Netty | 78,023 | 0 | 12.76 | 28.17 | 110.3% |
| Netty | 78,059 | 0 | 12.70 | 27.47 | 110.4% |
| Netty | 78,021 | 0 | 12.80 | 34.93 | 110.3% |
| Apache Tomcat | 14,966 | 0 | 66.66 | 125.24 | 21.1% |
| Apache Tomcat | 14,962 | 0 | 66.71 | 124.59 | 21.1% |
| Apache Tomcat | 14,761 | 0 | 67.62 | 147.34 | 20.8% |
| Undertow | 6,826 | 0 | 146.11 | 182.30 | 9.6% |
| Undertow | 6,792 | 0 | 146.83 | 184.29 | 9.6% |
| Undertow | 6,778 | 0 | 147.13 | 191.21 | 9.5% |

**See [docs/BENCHMARKS.md](docs/BENCHMARKS.md)** for the full 6-scenario breakdown across self / jetty / tomcat / netty — including HTTP/1, CPU-bound, multiplexed stream concurrency, browser-shape connection concurrency, large-response throughput, and per-scenario rationale on what each scenario was designed to expose.

_Benchmark performed 2026-05-21 on Darwin, arm64, 10 cores, Apple M4, 24GB RAM (MacBook Air)._
_OS: macOS 15.7.3._
_Java: openjdk version "25.0.2" 2026-01-20 LTS._
<!-- PERF-SUMMARY-END -->

_JDK HttpServer (`com.sun.net.httpserver`) is included as a baseline since it ships with the JDK and requires no dependencies. However, as the stress test shows, it is not suitable for production workloads — it suffers significant failures under high concurrency._
See [benchmarks/README.md](benchmarks/README.md) for full usage and options.

_Benchmark performed 2026-02-19 on Darwin, arm64, 10 cores, Apple M4, 24GB RAM (MacBook Air)._
_OS: macOS 15.7.3._
_Java: openjdk version "21.0.10" 2026-01-20._
## Protocol support

To reproduce:
```bash
cd benchmarks
./run-benchmarks.sh --scenarios hello,high-concurrency
./update-readme.sh
```
Detailed conformance status lives in the per-version spec docs:

See [benchmarks/README.md](benchmarks/README.md) for full usage and options.
- [HTTP/1.1](docs/design/2026-04-27-HTTP1.1.md) — implemented
- [HTTP/2](docs/design/2026-05-05-HTTP2.md) — implemented (RFC 9113, HPACK, h2c, ALPN, gRPC)
- [HTTP/3](docs/design/2026-05-09-HTTP3.md) — out of scope until JDK QUIC API

## Todos and Roadmap

### Server tasks

* [x] Basic HTTP 1.1
* [x] Support Accept-Encoding (gzip, deflate), by default and per response options.
* [x] Support Content-Encoding (gzip, deflate)
* [x] Support Keep-Alive
* [x] Support Expect-Continue 100
* [x] Support Transfer-Encoding: chunked on request for streaming.
* [x] Support Transfer-Encoding: chunked on response
* [x] Support cookies in request and response
* [x] Support form data
* [x] Support multipart form data
* [x] Support TLS
* [ ] Support trailers
* [ ] Support HTTP 2

### Client tasks

* [ ] Basic HTTP 1.1
* [ ] Support Keep-Alive
* [ ] Support TLS
* [ ] Support Expect-Continue 100
* [ ] Support chunked request and response
* [ ] Support streaming entity bodies
* [ ] Support form data
* [ ] Support multipart form data
* [ ] Support HTTP 2
The HTTP client is not yet implemented.

## FAQ

Expand Down
Loading